जावास्क्रिप्ट में सरणी के लिए एक डोम नोड सूची में कैसे परिवर्तित करें?


96

मेरे पास एक जावास्क्रिप्ट फ़ंक्शन है जो HTML नोड्स की एक सूची को स्वीकार करता है, लेकिन यह एक जावास्क्रिप्ट सरणी की अपेक्षा करता है (यह उस पर कुछ ऐरे तरीके चलाता है) और मैं इसे उसी Document.getElementsByTagNameडोम के नोड रिटर्न की सूची के आउटपुट को खिलाना चाहता हूं ।

शुरू में मैंने कुछ सरल का उपयोग करने की सोची:

Array.prototype.slice.call(list,0)

और यह सभी ब्राउज़रों में ठीक काम करता है, बेशक इंटरनेट एक्सप्लोरर जो "JScript ऑब्जेक्ट अपेक्षित" त्रुटि देता है, जैसा कि जाहिरा तौर पर DOM नोड सूची Document.getElement*विधियों द्वारा लौटाया गया है, फ़ंक्शन कॉल का लक्ष्य होने के लिए JScript ऑब्जेक्ट पर्याप्त नहीं है।

कैविट्स: मुझे इंटरनेट एक्सप्लोरर विशिष्ट कोड लिखने में कोई आपत्ति नहीं है, लेकिन मुझे JQuery जैसे किसी भी जावास्क्रिप्ट लाइब्रेरी का उपयोग करने की अनुमति नहीं है क्योंकि मैं एक विजेट को 3 पार्टी वेब साइट में एम्बेड करने के लिए लिख रहा हूं, और मैं बाहरी पुस्तकालयों को लोड नहीं कर सकता ग्राहकों के लिए संघर्ष पैदा करेगा।

मेरी आखिरी खाई का प्रयास डोम नोड की सूची पर चलना और खुद एक सरणी बनाना है, लेकिन क्या ऐसा करने का एक अच्छा तरीका है?


बेहतर अभी तक, डोम नोड सूची से परिवर्तित करने के लिए एक फ़ंक्शन बनाएं, लेकिन यह वास्तव में मेरा समाधान होगा, मुझे लगता है कि आपने इसे सही पाया।
क्रिस्टोफ़र साल्-स्टोर्गार्ड

> के लिए (i = 0; मैं & lt; x.length; i ++) प्रत्येक पुनरावृत्ति पर नोडलिस्ट की लंबाई क्यों मिलती है? यह न केवल समय की बर्बादी है, बल्कि चूंकि नोडलिस्ट लाइव संग्रह हैं, अगर लूप के शरीर में कुछ भी अपनी लंबाई बदलता है, तो आप अंतहीन रूप से लूप कर सकते हैं या एक इंडेक्स आउट-ऑफ-बाउंड मार सकते हैं। उत्तरार्द्ध सबसे खराब है जो तब हो सकता है जब आप एक चर को लंबाई निर्दिष्ट करते हैं, और एक त्रुटि अंतहीन लूप की तुलना में बहुत बेहतर है।

यह वास्तव में एक पुराना सवाल है, लेकिन jQuery को .noCflflict विधि के साथ विशेष रूप से बनाया गया था ताकि यह अन्य पुस्तकालयों (यहां तक ​​कि) के साथ संघर्ष का कारण न बने, जिसका अर्थ है कि jQuery के कई संस्करणों को एक पृष्ठ पर लोड किया जा सकता है। कहा कि, पुस्तकालय का उपयोग / लोड करने से बचना सबसे अच्छा है जब तक कि आपके पास बिल्कुल न हो।
Vol7ron

@ vol7ron: 2016 के लिए तेजी से आगे, और हर कोई अभी भी उस आकार के बारे में उत्साहित है जो जावास्क्रिप्ट पुस्तकालयों पृष्ठ पर जोड़ता है। दी गई, JQuery की मिनिमाइज्ड और gzipped 30KB है, इसका अभी भी 30KB बहुत ज्यादा है बस एक नोड लिस्ट को बदलने के लिए :-)
Guss

जवाबों:


64

NodeLists होस्ट ऑब्जेक्ट्स हैं , होस्ट ऑब्जेक्ट्सArray.prototype.slice पर विधि का उपयोग करके काम करने की गारंटी नहीं है, ECMAScript विनिर्देश राज्यों:

क्या स्लाइस फ़ंक्शन को होस्ट ऑब्जेक्ट पर सफलतापूर्वक लागू किया जा सकता है, कार्यान्वयन-निर्भर है।

मैं आपको एक सरल कार्य करने के लिए सुझाव दूंगा कि इसमें एक से बढ़ NodeListकर एक सरणी में प्रत्येक मौजूदा तत्व जोड़ा जाए:

function toArray(obj) {
  var array = [];
  // iterate backwards ensuring that length is an UInt32
  for (var i = obj.length >>> 0; i--;) { 
    array[i] = obj[i];
  }
  return array;
}

अपडेट करें:

जैसा कि अन्य उत्तर बताते हैं, अब आप आधुनिक वातावरण में फैल सिंटैक्स या Array.fromविधि का उपयोग कर सकते हैं :

const array = [ ...nodeList ] // or Array.from(nodeList)

लेकिन इसके बारे में सोचते हुए, मुझे लगता है कि एक नोडरेस्ट को एक ऐरे में बदलने के लिए सबसे आम उपयोग का मामला है, इस पर पुनरावृति करना, और अब NodeList.prototypeऑब्जेक्ट में forEachमूल रूप से विधि है , इसलिए यदि आप एक आधुनिक वातावरण में हैं तो आप इसे सीधे उपयोग कर सकते हैं, या कर सकते हैं एक पोलीफ़िल।


2
यह उलट सूची के मूल क्रम के साथ एक सरणी बना रहा है, जो मुझे नहीं लगता कि ओपी चाहता है। क्या आप array[i] = obj[i]इसके बजाय करना array.push(obj[i])चाहते थे ?
टिम डाउन

@ सही, ठीक है, मैं इसे पहले की तरह था, लेकिन कल रात (3AM स्थानीय समय :), धन्यवाद के बिना संपादित किया! धन्यवाद!
क्रिश्चियन सी। साल्वादो

9
किन परिस्थितियों में obj.lengthकुछ और होगा तो पूर्णांक मान?
पीटर

1
मुझे विश्वास नहीं हो रहा है कि यह जटिल है। बदसूरत। यह वेब / जेएस प्रोग्रामिंग में एक बहुत ही आम जरूरत है। भाषा की अगली रिलीज के लिए एक नई विधि?
एंड्रयू कोपर

1
@AlbertoPerez, आपका स्वागत है! सालुदोस हस्टा मैड्रिड!
क्रिश्चियन सी। साल्वादो

126

में ES6 तुम सिर्फ इस प्रकार के रूप में उपयोग कर सकते हैं:

  • फैला हुआ संचालक

     var elements = [... nodelist]
  • का उपयोग करते हुए Array.from

     var elements = Array.from(nodelist)

https://developer.mozilla.org/en-US/docs/Web/API/NodeList पर अधिक संदर्भ


4
साथ इतना आसान Array.from(): D
जोसन इराचेता

4
यदि कोई व्यक्ति टाइपस्क्रिप्ट (ES5 के साथ) के साथ इस दृष्टिकोण का उपयोग कर रहा है, तो केवल Array.fromकाम करता है, क्योंकि टीएस इसे स्थानांतरित करता है nodelist.slice- जो समर्थित नहीं है।
पीटर अल्बर्ट

मैंने एक साल पहले ही आपको जवाब दिया था और आपने मुझे वोटों पर पारित किया था? मैं यह नहीं समझा सकता ..
vsync

3
@vsync, आपके उत्तर में उल्लेख नहीं हैArray.from
ESR

@EdmundReed - तो? यह कैसे सही है। यह लंबे समय तक लिखने के लिए है, इसलिए इसका उपयोग कभी नहीं किया जाएगा, केवल spreadइसका उपयोग किया जाता है।
vsync

16

स्प्रेड (ES2015) का उपयोग करना , यह उतना ही आसान है:[...document.querySelectorAll('p')]

(वैकल्पिक: बाबेल का उपयोग उपरोक्त ES6 कोड को ES5 सिंटैक्स में बदलने के लिए करें)


अपने ब्राउज़र के कंसोल में इसे आज़माएं और जादू देखें:

for( links of [...document.links] )
  console.log(links);

कम से कम नवीनतम क्रोम में, 44, मैं इसे प्राप्त करता हूं: अनकैप्ड टाइपर्रर: document.querySelectorAll कोई फ़ंक्शन नहीं है (…)
निक

@OmidHezaveh - जैसा कि मैंने कहा, यह ES6 कोड है। मुझे नहीं पता कि क्रोम 44 ईएस 6 का समर्थन करता है और यदि हां, तो किस कवरेज पर। यह लगभग एक वर्ष पुराना ब्राउज़र है और जाहिर है कि आपको इस कोड को एक ब्राउज़र पर चलाना होगा जो ES6 स्प्रेड का समर्थन करता है।
vsync

या क्रियान्वयन से पहले es5 करने के लिए इसे transpile
HelloWorld

8

इस सरल चाल का उपयोग करें

<Your array> = [].map.call(<Your dom array>, function(el) {
    return el;
})

क्या आप कृपया बता सकते हैं कि आपको क्यों लगता है कि इसका उपयोग करने की तुलना में सफलता का बेहतर मौका है Array.prototype.slice(या [].sliceजैसा कि आपने इसे रखा है)? एक नोट के रूप में, मैं टिप्पणी करना चाहूंगा कि क्यू में मैंने जिस IE विशिष्ट त्रुटि को दर्ज किया है वह IE 8 या उससे कम में होता है, जहां mapवैसे भी लागू नहीं किया जाता है। IE 9 ("मानक मोड") या उच्चतर में, दोनों एक ही तरीके से sliceऔर mapसफल होते हैं।
Guss

6

हालांकि यह वास्तव में एक उचित शिम नहीं है, क्योंकि डोम तत्वों के साथ काम करने की कोई कल्पना नहीं है, मैंने आपको slice()इस तरीके से उपयोग करने की अनुमति दी है: https://gist.github.com/brettz9/6093105

अद्यतन : जब मैंने इसे DOM4 युक्ति के संपादक के साथ उठाया (यह पूछते हुए कि क्या वे होस्ट ऑब्जेक्ट्स के लिए अपने स्वयं के प्रतिबंधों को जोड़ सकते हैं (ताकि कल्पना को कार्यान्वयनकर्ताओं की आवश्यकता हो तो इन वस्तुओं को सरणी विधियों के साथ उपयोग करने के लिए उचित रूप से परिवर्तित किया जा सकता है) कार्यान्वयन-स्वतंत्रता के लिए अनुमति दी गई), उन्होंने उत्तर दिया कि "होस्ट वस्तुएं ES6 / IDL की तुलना में कम या ज्यादा अप्रचलित हैं।" मैं प्रति http://www.w3.org/TR/WebIDL/#es-array देखता हूं कि चश्मा "प्लेटफ़ॉर्म एरे ऑब्जेक्ट्स" को परिभाषित करने के लिए इस आईडीएल का उपयोग कर सकते हैं, लेकिन http://www.w3.org/TR/domcore/ doesn ऐसा लगता है कि नई IDL का उपयोग नहीं किया जा HTMLCollectionरहा है (हालांकि ऐसा लग रहा है कि यह ऐसा हो सकता है, Element.attributesहालांकि यह केवल स्पष्ट रूप से बताता है कि यह DOMIDring और DOMTimeStamp के लिए WebIDL का उपयोग कर रहा है)। मैं देखता हूं[ArrayClass](जो Array.prototype से विरासत में मिला है) का उपयोगNodeList (औरNamedNodeMapअब एकमात्र आइटम के पक्ष में पदावनत किया जाता है जो अभी भी इसका उपयोग कर रहा है, Element.attributes)। किसी भी मामले में, ऐसा लगता है कि यह मानक बनना है। ईएस 6 Array.fromऐसे रूपांतरणों के लिए निर्दिष्ट करने Array.prototype.sliceऔर अधिक शब्दार्थ [].slice()(और छोटे रूप, और Array.slice()एक "सरणी जेनेरिक") की तुलना में अधिक सुविधाजनक हो सकता है, जहाँ तक मुझे पता है, मानक व्यवहार नहीं है)।


मैंने यह दर्शाने के लिए अपडेट किया है कि चश्मा इस व्यवहार की आवश्यकता की दिशा में आगे बढ़ सकता है।
ब्रेट ज़मीर

5

आज, 2018 में, हम ECMAScript 2015 (6 वें संस्करण) या ES6 का उपयोग कर सकते हैं, लेकिन सभी ब्राउज़र इसे समझ नहीं सकते हैं (उदाहरण के लिए। IE यह सब नहीं समझता है)। यदि आप चाहते हैं कि आप ES6 का उपयोग इस प्रकार कर सकते हैं: var array = [... NodeList];( प्रसार ऑपरेटर के रूप में ) या var array = Array.from(NodeList);

अन्य मामलों में (यदि आप ईएस 6 का उपयोग नहीं कर सकते हैं) तो आप ए NodeListको बदलने के लिए सबसे छोटा तरीका उपयोग कर सकते हैं Array:

var array = [].slice.call(NodeList, 0);

उदाहरण के लिए:

var nodeList = document.querySelectorAll('input');
//we use "{}.toString.call(Object).slice(8, -1)" to find the class name of object
console.log({}.toString.call(nodeList).slice(8, -1)); //NodeList

var array = [].slice.call(nodeList, 0);
console.log({}.toString.call(array).slice(8, -1)); //Array

var result = array.filter(function(item){return item.value.length > 5});

for(var i in result)
  console.log(result[i].value); //credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

लेकिन अगर आप DOMनोड लिस्ट को आसान बनाना चाहते हैं, तो आपको ए NodeListको कन्वर्ट करने की जरूरत नहीं है ArrayNodeListउपयोग में वस्तुओं पर लूप करना संभव है :

var nodeList = document.querySelectorAll('input');
// Calling nodeList.item(i) isn't necessary in JavaScript
for(var i = 0; i < nodeList.length; i++)
    console.log(nodeList[i].value); //trust, credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

सूची में आइटमों का उपयोग करने for...inया for each...inउन्हें एन्यूमरेट करने का लालच न करें , क्योंकि इससे लंबाई और आइटम गुणों की गणना भी हो जाएगी NodeListऔर त्रुटियों का कारण बन सकता है यदि आपकी स्क्रिप्ट यह मानती है कि केवल तत्व ऑब्जेक्ट्स से निपटना है। इसके अलावा, for..inकिसी विशेष क्रम में संपत्तियों का दौरा करने की गारंटी नहीं है।for...ofलूप्स नोडलिस्ट ऑब्जेक्ट्स पर सही ढंग से लूप करेंगे।

यह भी देखें:


3
var arr = new Array();
var x= ... get your nodes;

for (i=0;i<x.length;i++)
{
  if (x.item(i).nodeType==1)
  {
    arr.push(x.item(i));
  }
}

यह काम करना चाहिए, ब्राउज़र को पार करना चाहिए और आपको सभी "तत्व" नोड्स प्राप्त करना चाहिए।


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