नोडलिस्ट के पास क्यों नहीं है?


91

मैं <abbr>तत्वों के आंतरिक पाठ को बदलने के लिए एक छोटी स्क्रिप्ट पर काम कर रहा था , लेकिन पाया गया कि nodelistएक forEachविधि नहीं है । मुझे पता है कि nodelistसे विरासत में नहीं मिलता है Array, लेकिन ऐसा लगता नहीं है कि forEachएक उपयोगी तरीका होगा? क्या कोई विशेष कार्यान्वयन मुद्दा है जिसके बारे में मुझे जानकारी नहीं है कि इसमें जोड़ने forEachसे रोकता है nodelist?

नोट: मुझे पता है कि Dojo और jQuery दोनों forEachअपने नोडलिस्ट के लिए किसी न किसी रूप में हैं। मैं सीमाओं के कारण भी उपयोग नहीं कर सकता।


जवाबों:


94

NodeList में अब सभी प्रमुख ब्राउज़रों में forEach () है

एमडीएन पर नोडल फॉर ईच () देखें ।

मूल उत्तर

इनमें से कोई भी उत्तर यह नहीं समझाता है कि नॉडलिस्ट अर्रे से विरासत में क्यों नहीं मिली है, इस प्रकार यह forEachसभी और बाकी के लिए अनुमति देता है ।

इसका उत्तर इस पूर्व-चर्चा सूत्र पर मिलता है । संक्षेप में, यह वेब को तोड़ता है:

यह समस्या कोड थी जिसे गलत तरीके से उदाहरण के रूप में माना गया था कि यह उदाहरण Array.prototype.confat के साथ संयोजन में एक सरणी था।

Google के बंद पुस्तकालय में एक बग था, जिसके कारण लगभग सभी Google के ऐप्स विफल हो गए थे। यह मिलते ही लाइब्रेरी को अपडेट कर दिया गया था, लेकिन वहां अभी भी कोड आउट हो सकता है जो कॉनकैट के संयोजन में एक ही गलत धारणा बनाता है।

यानी कुछ कोड ने कुछ ऐसा किया

if (x instanceof Array) {
  otherArray.concat(x);
} else {
  doSomethingElseWith(x);
}

हालांकि, concatअन्य वस्तुओं से "वास्तविक" सरणियों (उदाहरण के लिए एरियर) को अलग तरीके से व्यवहार करेंगे:

[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat(4) // [1, 2, 3, 4]

तो इसका मतलब है कि उपरोक्त कोड तब टूट xगया था जब एक नोडलिस्ट था, क्योंकि इससे पहले कि वह नीचे चला गया था doSomethingElseWith(x), जबकि बाद में यह otherArray.concat(x)रास्ते से नीचे चला गया , जो कि कुछ अजीब xथा क्योंकि यह एक वास्तविक सरणी नहीं था।

कुछ समय के लिए एक Elementsवर्ग के लिए एक प्रस्ताव था जो कि ऐरे का वास्तविक उपवर्ग था, और इसे "नए नोडलिस्ट" के रूप में उपयोग किया जाएगा। हालाँकि, इसे डोम स्टैंडर्ड से हटा दिया गया था , कम से कम अभी के लिए, क्योंकि यह तकनीकी और विनिर्देश-संबंधित कारणों के लिए अभी तक लागू करने के लिए संभव नहीं था।


11
मुझे एक बुरा कॉल लगता है। गंभीरता से, मुझे लगता है कि सामान को एक बार में तोड़ने का सही निर्णय है, खासकर अगर इसका मतलब है कि हमारे पास भविष्य के लिए एपीआई एपीआई हैं। इसके अलावा, इसकी वेब की तरह एक स्थिर मंच होने के करीब भी नहीं है, लोगों को उनके 2 साल पुराने जावास्क्रिप्ट का उपयोग किया जाता है जो अब अपेक्षित रूप से कार्य नहीं कर रहा है ..
JoyalToTheWorld

3
"वेब तोड़ता है"! = "Google सामग्री तोड़ता है"
मैट

क्यों न केवल Array.prototyp से forEach विधि उधार लें? जैसे कि ऐरे को प्रोटोटाइप के रूप में जोड़ने के बजाय, बस ऐसा करें। कंस्ट्रक्टर में यह करें। Array.prototype.forEach, या यहां तक ​​कि सिर्फ NodeList के लिए विशिष्ट रूप से लागू करें?
पॉपकर्न

1
ध्यान दें; इस अद्यतन से यह NodeList now has forEach() in all major browsersप्रतीत होता है कि IE एक प्रमुख ब्राउज़र नहीं है। उम्मीद है कि कुछ लोगों के लिए यह सच है, लेकिन यह मेरे लिए (अभी तक) सच नहीं है।
ग्राहम पी हीथ

58

तुम कर सकते हो

Array.prototype.forEach.call (nodeList, function (node) {

    // Your code here.

} );

3
Array.prototype.forEach.callको कम किया जा सकता है[].forEach.call
CodeBrauer

7
@CodeBrauer: यह सिर्फ छोटा नहीं है Array.prototype.forEach.call, यह एक खाली सरणी बना रहा है और इसकी forEachविधि का उपयोग कर रहा है।
पॉल डी। वेट

34

आप नोड्स की एक नई सरणी बनाने पर विचार कर सकते हैं।

  var nodeList = document.getElementsByTagName('div'),

      nodes = Array.prototype.slice.call(nodeList,0); 

  // nodes is an array now.
  nodes.forEach(function(node){ 

       // do your stuff here.  

  });

नोट: यह केवल उन नोड संदर्भों की एक सूची / सरणी है, जो हम यहां बना रहे हैं, कोई डुप्लिकेट नोड्स नहीं।

  nodes[0] === nodeList[0] // will be true

22
या बस करो Array.prototype.forEach.call(nodeList, fun)
अनकुहन

मैं भी foreach समारोह ऐसा है कि aliasing सुझाव है: var forEach = Array.prototype.forEach.call(nodeList, callback);। अब आप बस कॉल कर सकते हैंforEach(nodeList, callback);
एंड्रयू Craswell

19

कभी मत कहो, यह 2016 है और NodeListवस्तु ने forEachनवीनतम क्रोम में एक विधि लागू की है (v52.0.2743.116)।

इसे उत्पादन में उपयोग करना जल्दबाजी होगी क्योंकि अन्य ब्राउज़र अभी तक इसका समर्थन नहीं करते हैं (FF 49 का परीक्षण किया गया है) लेकिन मुझे लगता है कि यह जल्द ही मानकीकृत हो जाएगा।


2
ओपेरा भी इसका समर्थन करता है और समर्थन फ़ायरफ़ॉक्स के v50 में जोड़ा जाएगा, जो 15/11/16 को रिलीज़ के लिए निर्धारित है।
झबरा

1
हालांकि इसे लागू किया गया, यह किसी भी मानक का हिस्सा नहीं है। यह अभी भी सबसे अच्छा है Array.prototype.slice.call(nodelist).forEach(…)जो मानक है और पुराने ब्राउज़रों में काम करता है।
नैट

17

संक्षेप में, इसका डिज़ाइन उस पद्धति को लागू करने के लिए संघर्ष करता है।

MDN से:

मैं NodeList पर forEach या मैप का उपयोग क्यों नहीं कर सकता?

NodeList को सरणियों की तरह बहुत अधिक उपयोग किया जाता है और यह उन पर Array.prototype विधियों का उपयोग करने के लिए आकर्षक होगा। हालांकि, यह असंभव है।

प्रोटोटाइप के आधार पर जावास्क्रिप्ट में एक विरासत तंत्र है। सरणी उदाहरण विरासत विधि (जैसे कि forEach या मैप) का उदाहरण देते हैं क्योंकि उनकी प्रोटोटाइप श्रृंखला निम्न की तरह दिखाई देती है:

myArray --> Array.prototype --> Object.prototype --> null (किसी वस्तु की प्रोटोटाइप श्रृंखला को कई बार Object.getPrototypOf पर कॉल करके प्राप्त किया जा सकता है)

forEach, map और पसंद Array.prototype ऑब्जेक्ट के अपने गुण हैं।

सरणियों के विपरीत, नोडलिस्ट प्रोटोटाइप श्रृंखला निम्नलिखित की तरह दिखती है:

myNodeList --> NodeList.prototype --> Object.prototype --> null

NodeList.prototype में आइटम विधि होती है, लेकिन Array.prototype विधियों में से कोई भी नहीं, इसलिए उनका उपयोग NodeLists पर नहीं किया जा सकता है।

स्रोत: https://developer.mozilla.org/en-US/docs/DOM/NodeList (नीचे स्क्रॉल करें मैं NodeList पर forEach या मैप का उपयोग क्यों नहीं कर सकता? )


8
इसलिए, चूंकि यह एक सूची है, इसलिए इसे इस तरह से क्यों बनाया गया है? उन्हें चेन बनाने के लिए क्या रोक रहा था myNodeList --> NodeList.prototype --> Array.prototype --> Object.prototype --> null:?
इगोर पेंतोविक

14

यदि आप NodeList पर forEach का उपयोग करना चाहते हैं, तो उस फ़ंक्शन को Array से कॉपी करें:

NodeList.prototype.forEach = Array.prototype.forEach;

Thats सब, अब आप इसे उसी तरीके से उपयोग कर सकते हैं जिस तरीके से आप ऐरे करेंगे:

document.querySelectorAll('td').forEach(function(o){
   o.innerHTML = 'text';
});

4
सिवाय इसके कि आधार कक्षाओं को परिवर्तित करना औसत पाठक के लिए बहुत स्पष्ट नहीं है। किसी कोड में गहरे दूसरे शब्दों में आपको ब्राउज़र बेस ऑब्जेक्ट्स में किए गए हर अनुकूलन को याद रखना होगा। MDN प्रलेखन पर भरोसा करना अब उपयोगी नहीं है क्योंकि वस्तुओं ने आदर्श से व्यवहार को बदल दिया है। कॉल समय पर प्रोटोटाइप को स्पष्ट रूप से लागू करना बेहतर होता है ताकि पाठक आसानी से महसूस कर सके कि फॉरएच एक उधार लिया गया विचार है और ऐसा कुछ नहीं जो भाषा की परिभाषा का हिस्सा हो। जवाब देखिए @akuhn के ऊपर है।
सुकिमा

@ सुकीमा गलत परिसरों से गुमराह हुई। इस विशिष्ट मामले में, दिया गया दृष्टिकोण डेवलपर द्वारा अपेक्षित व्यवहार करने के लिए NodeList को ठीक करता है। यह सिस्टम क्लास समस्या को ठीक करने का सबसे उचित तरीका है। (NodeList अधूरा लगता है और भाषा के भविष्य के संस्करणों में तय किया जाना चाहिए।)
डैनियल Garmoshka

1
अब जब NodeList.forEach मौजूद है, यह एक प्रफुल्लित करने वाला सरल पॉलीफ़िल बन जाता है!
डेमन

7

ES2015 में, आप अब forEachनोडलिस्ट के लिए विधि का उपयोग कर सकते हैं ।

document.querySelectorAll('abbr').forEach( el => console.log(el));

एमडीएन लिंक देखें

हालाँकि यदि आप HTML संग्रह या अन्य सरणी जैसी वस्तुओं का उपयोग करना चाहते हैं, तो es2015 में, आप Array.from()विधि का उपयोग कर सकते हैं । यह विधि एक सरणी-जैसी या पुनरावृत्त वस्तु (नोडलिस्ट, HTML संग्रह, तार आदि सहित) लेती है और एक नया धोखा उदाहरण देता है। आप इसे इस तरह से उपयोग कर सकते हैं:

const elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( el => console.log(el));

जैसा कि Array.from()विधि शमनीय है, आप इसे इस तरह से es5 कोड में उपयोग कर सकते हैं

var elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( function(el) {
    console.log(el);
});

विवरण के लिए, MDN पृष्ठ देखें ।

वर्तमान ब्राउज़र समर्थन की जांच करने के लिए ।

या

एक और es2015 रास्ता प्रसार ऑपरेटर का उपयोग करना है।

[...document.querySelectorAll('abbr')].forEach( el => console.log(el));

MDN फैल ऑपरेटर

स्प्रेड ऑपरेटर - ब्राउज़र सपोर्ट


2

मेरा समाधान:

//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;

1
यह अक्सर प्रोटोटाइप के माध्यम से डोम की कार्यक्षमता का विस्तार करने के लिए एक अच्छा विचार नहीं है, विशेष रूप से IE ( लेख ) के पुराने संस्करणों में ।
KFE

0

NodeList DOM API का हिस्सा है। ECMAScript बाइंडिंग को देखें जो जावास्क्रिप्ट पर भी लागू होते हैं। http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html । नोडलिस्ट और रीड-ओनली लेंथ प्रॉपर्टी और आइटम (इंडेक्स) नोड को वापस करने के लिए कार्य करते हैं।

जवाब है, आपको पुनरावृति करनी होगी। यहां कोई विकल्प नहीं है। फॉरच काम नहीं करेगा। मैं जावा डोम एपीआई बाइंडिंग के साथ काम करता हूं और यही समस्या है।


लेकिन क्या कोई खास वजह है कि इसे लागू नहीं किया जाना चाहिए? JQuery और Dojo दोनों ने इसे अपने स्वयं के पुस्तकालयों
सांप और कॉफी

2
लेकिन यह एक डिजाइन संघर्ष कैसे है?
सांप और कॉफी

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.