wake-up-neo.com

Warum gibt es keine Nodeliste?

Ich habe an einem kurzen Skript gearbeitet, um den inneren Text von <abbr>-Elementen zu ändern, aber ich habe festgestellt, dass nodelist keine forEach-Methode hat. Ich weiß, dass nodelist nicht von Array erbt, aber scheint es, als wäre forEach eine nützliche Methode? Gibt es ein bestimmtes Implementierungsproblem, von dem ich nicht weiß, dass das Hinzufügen von forEach zu nodelist verhindert wird?

Hinweis: Mir ist bekannt, dass Dojo und jQuery beide forEach für ihre Knotenlisten haben. Ich kann beide aufgrund von Einschränkungen nicht verwenden.

79

NodeList hat jetzt forEach () in allen gängigen Browsern

Siehe nodeList forEach () zu MDN .

Ursprüngliche Antwort

Keine dieser Antworten erklärt , warum NodeList nicht von Array erbt, so dass forEach und der Rest übrig bleibt.

Die Antwort ist in diesem Es-Discussion-Thread . Kurz gesagt, es bricht das Web:

Das Problem war ein Code, der fälschlicherweise eine Instanz davon annahm, um darauf hinzuweisen, dass die Instanz ein Array in Kombination mit Array.prototype.concat war.

In der Closure Library von Google ist ein Fehler aufgetreten, der dazu geführt hat, dass fast alle Apps von Google aus diesem Grund fehlschlagen. Die Bibliothek wurde aktualisiert, sobald dies gefunden wurde. Möglicherweise gibt es jedoch noch Code, der dieselbe falsche Annahme in Kombination mit concat macht.

Das heißt, irgendein Code hat so etwas gemacht

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

concat behandelt jedoch "echte" Arrays (keine Instanz von Array) anders als andere Objekte:

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

das bedeutet, dass der obige Code brach, als x eine NodeList war, denn bevor er den doSomethingElseWith(x)-Pfad hinunterging, ging er später den otherArray.concat(x)-Pfad hinunter, was etwas seltsames tat, da x keine war reales Array.

Für einige Zeit gab es einen Vorschlag für eine Elements Klasse, die eine echte Unterklasse von Array war und als "die neue NodeList" verwendet werden sollte. Dies wurde jedoch aus dem DOM-Standard entfernt zumindest für jetzt, da eine Implementierung aus verschiedenen technischen und spezifikationsbezogenen Gründen noch nicht möglich war.

80
Domenic

Du kannst tun

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

    // Your code here.

} );
48
akuhn

Sie können ein neues Knotenfeld erstellen. 

  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.  

  });

Hinweis: Dies ist nur eine Liste/Array von Knotenreferenzen, die wir hier erstellen, keine doppelten Knoten.

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

Sag niemals nie, es ist 2016 und das NodeList-Objekt hat eine forEach-Methode im neuesten Chrome (v52.0.2743.116) implementiert.

Es ist zu früh, um es in der Produktion zu verwenden, da andere Browser dies noch nicht unterstützen (FF 49 getestet), aber ich denke, dass dies bald standardisiert wird.

18
maioman

Kurz gesagt, es ist ein Entwurfskonflikt bei der Implementierung dieser Methode.

Von MDN:

Warum kann ich forEach oder eine Map in einer NodeList nicht verwenden?

NodeList werden sehr ähnlich wie Arrays verwendet und es wäre verlockend, Verwenden Sie Array.prototype-Methoden für sie. Dies ist jedoch unmöglich.

JavaScript verfügt über einen Vererbungsmechanismus, der auf Prototypen basiert. Array Instanzen erben Array-Methoden (wie forEach oder map), weil ihre Prototypkette sieht wie folgt aus:

myArray --> Array.prototype --> Object.prototype --> null (die Prototypkette eines Objekts kann durch mehrmaliges Aufrufen von Object.getPrototypeOf abgerufen werden.)

forEach, map und die Likes sind eigene Eigenschaften des Array.prototype Objekt.

Im Gegensatz zu Arrays sieht die Prototypkette von NodeList wie folgt aus:

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

NodeList.prototype enthält die item-Methode, jedoch keine der Array.prototype-Methoden, daher können sie nicht für NodeLists verwendet werden.

Quelle: https://developer.mozilla.org/en-US/docs/DOM/NodeList (scrollen Sie zu Warum kann ich nicht forEach oder eine Karte in einer NodeList verwenden?

15
Matt Lo

Wenn Sie forEach in NodeList verwenden möchten, kopieren Sie diese Funktion einfach aus Array:

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

Das ist alles, jetzt können Sie es auf die gleiche Weise verwenden, wie Sie es für Array tun würden:

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

In ES2015 können Sie jetzt die forEach-Methode für die nodeList verwenden.

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

Siehe MDN Link

Wenn Sie jedoch HTML-Sammlungen oder andere Array-ähnliche Objekte verwenden möchten, können Sie in es2015 die Methode Array.from() verwenden. Diese Methode nimmt ein Array-ähnliches oder iterierbares Objekt (einschließlich nodeList, HTML Collections, Strings usw.) und gibt eine neue Array-Instanz zurück. Sie können es so verwenden:

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

Da die Array.from()-Methode shimmbar ist, können Sie sie wie folgt in es5-Code verwenden

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

Einzelheiten finden Sie auf der Seite MDN .

So überprüfen Sie Unterstützung des aktuellen Browsers .

ODER

eine andere Methode von es2015 ist der Spread-Operator.

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

MDN-Verteilungsoperator

Spread Operator - Browserunterstützung

4

Meine Lösung: 

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

NodeList ist Teil der DOM-API. Schauen Sie sich die ECMAScript-Bindungen an, die auch für JavaScript gelten. http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html . Die nodeList und eine schreibgeschützte Längen- und Element (index) -Funktion zum Zurückgeben eines Knotens. 

Die Antwort ist, Sie müssen iterieren. Es gibt keine Alternative. Foreach wird nicht funktionieren .. Ich arbeite mit Java-DOM-API-Bindungen und habe das gleiche Problem. 

Überprüfen Sie die MDN auf NodeList.forEach .

NodeList.forEach(function(item, index, nodeList) {
    // code block here
});

Verwenden Sie im IE akuhns Antwort :

[].forEach.call(NodeList, function(item, index, array) {
    // code block here
});
0
VesperX