Was ist in Javascript der beste Weg, um eine NodeList in ein Array zu konvertieren?

81

Die DOM-Methode document.querySelectorAll()(und einige andere) geben a zurück NodeList.

Um die Liste zu bearbeiten, z. B. mit forEach(), NodeListmuss zuerst die Liste in eine konvertiert werden Array.

Was ist der beste Weg, um das NodeListin ein umzuwandeln Array?

cc jung
quelle
1
Ich denke, der Rückgabewert von querySelectorAll () wird technisch als NodeList bezeichnet.
jfriend00
von mdm "elementList = document.querySelectorAll (Selektoren);"
CC junge
1
elementList ist der Variablenname. Auf derselben Seite wird beschrieben, wie der Typ des Rückgabewerts eine NodeList ist.
jfriend00
danke für die Korrektur - in Frage gestellt
cc junge

Antworten:

66

Mit ES6 können Sie einfach Folgendes tun:

const spanList = [...document.querySelectorAll("span")];
Freezystem
quelle
Dies gibt mirType 'NodeListOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Rückruf
Hallo @callback, dies scheint ein TypeScript-Fehler zu sein. Möglicherweise haben Sie sich für die es6-Kompilierung entschieden, ohne "es6" im lib-Array Ihrer tsconfig-Datei hinzuzufügen. Grüße
Freezystem
1
Hallo @Freezystem, du hast recht! Ich ziele auf es2015. Vielen Dank!
Rückruf
@callback ES6 und ES2015 sind dasselbe
DarkNeuron
64

Mit ES6 können Sie verwenden Array.from(myNodeList). Verwenden Sie dann Ihre bevorzugte Array-Methode.

var myNodeList = document.querySelectorAll('.my-selector');

// ALT 1
Array.from(myNodeList).forEach(function(el) {
  console.log(el);
});

Verwenden Sie eine ES6-Unterlegscheibe , damit dies auch in älteren Browsern funktioniert.


Wenn Sie einen Transpiler verwenden (zum Beispiel Babel), gibt es zwei weitere Alternativen:

var myNodeList = document.querySelectorAll('.my-selector');

// ALT 2
for (var el of myNodeList) {
  el.classList.add('active'); // or some other action
}

// ALT 3
[...myNodeList].forEach((el) => {
  console.log(el);
});
Sandstrom
quelle
Stimmt es nicht auch unter es6, dass eine NodeList einen Iterator liefert?
CC Young
4
@ccyoung, aber der Iterator funktioniert nicht in nicht kompatiblen ES6-Browsern, da Sie Array.from(myNodeList)das Symbolobjekt nicht shimen können. Daher ist es besser, es zu verwenden, da es shimmed werden kann.
Roc
Ich habe also dieses Problem, bei dem Array.from (el.childNodes) den ersten Knoten nicht als Teil des Arrays zurückgibt.
Zinoadidi
48

Sie können es mithilfe der sliceMethode aus dem ArrayPrototyp in ein Array konvertieren :

var elList = document.querySelectorAll('.viewcount');
elList = Array.prototype.slice.call(elList, 0);

Wenn darüber hinaus alles , was Sie brauchen , ist forEach, können Sie aufrufen , dass aus dem ArrayPrototyp, ohne dass es zu einem Array Nötigung zuerst:

var elList = document.querySelectorAll('.viewcount');
Array.prototype.forEach.call(elList, function(el) {
    console.log(el);
});

In ES6 können Sie die neue Array.fromFunktion verwenden, um sie in ein Array zu konvertieren:

Array.from(elList).forEach(function(el) {
    console.log(el);
});

Dies ist derzeit nur in hochmodernen Browsern der Fall. Wenn Sie jedoch einen Polyfill-Dienst verwenden , haben Sie auf der ganzen Linie Zugriff auf diese Funktion.


Wenn Sie einen ES6-Transpiler verwenden , können Sie for..ofstattdessen sogar eine Schleife verwenden:

for (var element of document.querySelectorAll('.some .elements')) {
  // use element here
}
Joseph Silber
quelle
Vielen Dank. unter neueren Javascript-Gedanken / Hoffnungen gab es einen prägnanteren Zwang.
CC junge
6
@cc young - Beachten Sie, dass der Grund, den ich Array.prototype.forEachanstelle von verwende [].forEach, darin besteht, dass letzteres ein neues Array-Objekt erstellt, was völlig unnötig ist.
Joseph Silber
@ JosephSilber ahh danke - das ist das neue Array, das erstellt wurde, ist das leere []? Ich denke, dass dadurch Müll gesammelt wird und die Auswirkungen auf das Gedächtnis vernachlässigbar sind. Kann jemand dies kommentieren?
Daniel Sokolowski
@ Daniel das ist wahr, aber es gibt immer noch die Berechnung des Erstellens und Zerstörens des Arrays.
Brett
21

Warum konvertieren? - nur callFunktion des Arrays direkt auf der Elementsammlung;)

[].forEach.call( $('a'), function( v, i) {
    // do something
});

vorausgesetzt $ ist Ihr Alias für querySelectorAll , natürlich


Bearbeiten: ES6 ermöglicht eine noch kürzere Syntax [...$('a')]( funktioniert nur in Firefox, Stand Mai 2014 )

c69
quelle
Vorausgesetzt $ist querySelectorAll.
c69
3
Ihre Antwort impliziert die Verwendung von jQuery. Wenn das der Fall ist, ist diese Dummheit dank .each().
Matt Ball
1
lol Warum ? Nichts verbietet dir, Aliase wie zu machen function $ ( s ) { return document.querySelectorAll(s); }.
c69
5
Wenn Sie jQuery verwenden möchten, ist die prägnantere Lösung:$('a').each(function(i, v) {...});
jfriend00
2
offtopic: EcmaScript 5 ist bereits seit einem Jahr ein Standard. Alle Browser der aktuellen Generation unterstützen die neuen Methoden von Arrays, und es ging speziell um die Verwendung dieser Methoden in der NodeList aka Element-Sammlung.
c69
9

Muss es sein forEach? Sie können einfach eine forSchleife verwenden, um die Liste zu durchlaufen:

for (var i = 0; i < elementList.length; i++) {
    doSomethingWith(elementlist.item(i));
}
nfechner
quelle
1
+1 für die einfache Lösung, bei der keine unnötigen Array-Konvertierungen hinzugefügt werden. Zu elementList.item(i)Ihrer Information, stattdessen könnten Sie einfach verwenden elementList[i].
jfriend00
4
persönlich finde ich forEach()einen besseren Programmierstil und weniger ausführlich - ymmv
cc young
@cc young: Eigentlich stimme ich dir zu. Außer in solchen Fällen, in denen ich eine Konvertierung durchführen müsste, damit ich mein Lieblingsmuster verwenden kann. Das macht es klobig und sieht aus wie: "Wenn Sie nur einen Hammer haben, sieht alles aus wie ein Nagel."
Nfechner
Und hier ist ein verrückter Weg :) for (var oElement, i = 0; oElement = aMenuItemsElements; i++ { console.log(oElement); }
Daniel Sokolowski
Das Problem hierbei ist, dass Sie keine weitere for (var i…)Schleife verschachteln können , da die for-Schleife keinen eigenen Bereich erstellt (wie dies jetzt in C / C ++ der Fall ist). Und dann wird das idurcheinander gebracht.
Jens
9

Update 2020: nodeList.forEach () ist jetzt ein offizieller Standard und wird in allen aktuellen Browsern unterstützt.

Ältere Browser können die unten stehende Polyfüllung verwenden.

Um die Liste in Javascript zu bearbeiten, z. B. mit forEach (), muss die NodeList in ein Array konvertiert werden.

Das ist nicht wahr. .forEach()funktioniert in aktuellen Browsern. Wenn es fehlt, können Sie .forEach () von Array zu NodeList hinzufügen und es funktioniert einwandfrei :

if ( ! NodeList.prototype.forEach ) {
  NodeList.prototype.forEach = Array.prototype.forEach;
}

Sie können jetzt ausführen:

myNodeList.forEach(function(node){...})

Um wie bei Arrays über NodeLists zu iterieren.

Dies erzeugt überall viel kürzeren und saubereren Code als .call ().

Mikemaccana
quelle
1
Diese Antwort war genau das, was ich brauchte und diese 3 Zeilen sparten viel Zeit. Alle anderen Antworten hätten das Ändern einer Reihe von Code erforderlich gemacht, und ich verstehe nicht, warum.
Scribblemacher
Abstimmungen waren wahrscheinlich darauf zurückzuführen, dass das Patchen von eingebauten Prototypen durch Affen als schlechte Praxis angesehen wird
DuBistKomisch
@DuBistKomisch Dies ist eine Polyfüllung, die nur angewendet wird, wenn der Standard NodeList.foreach () nicht vorhanden ist.
Mikemaccana
1
ah mein schlechtes, wusste nicht, dass sie tatsächlich forEachspeziell hinzugefügt haben , ich kam hierher auf der Suche nachfilter
DuBistKomisch
@DuBistKomisch Sie können dieselbe Technik für verwenden filter, möchten jedoch möglicherweise einen inoffiziellen Namen NodeList.prototype.dbkFilteroder einen ähnlichen Namen vergeben, wenn Sie sich Sorgen über einen zukünftigen Standard mit einer anderen Implementierung machen.
Mikemaccana
2

ES6 erlaubt coole Wege wie, var nodeArray = Array.from(nodeList)aber mein Favorit ist der neue Spread-Operator.

var nodeArray = Array(...nodeList);
Reduzieren
quelle
Eine perfekte Lösung! Diese Lösung gilt auch für Typescript.
Nirus
Ich möchte hinzufügen, dass dies nur mit TypeScript funktioniert, solange Sie nicht auf ES5 oder niedriger transpilieren.
Rudey
2

Das hat bei mir in ES6 funktioniert

Nehmen wir an, Sie haben eine solche Knotenliste

<ul>
  <li data-time="5:17">Flexbox video</li>
  <li data-time="8:22">Flexbox video</li>
  <li data-time="3:24">Redux video</li>
  <li data-time="5:17">Flexbox video</li>
  <li data-time="7:17">Flexbox video</li>
  <li data-time="4:17">Flexbox video</li>
  <li data-time="2:17">Redux video</li>
  <li data-time="7:17">Flexbox video</li>
  <li data-time="9:54">Flexbox video</li>
  <li data-time="5:53">Flexbox video</li>
  <li data-time="7:32">Flexbox video</li>
  <li data-time="2:47">Redux video</li>
  <li data-time="9:17">Flexbox video</li>

</ul>


const items = Array.from(document.querySelectorAll('[data-time]'));

console.log(items);
Amr.Ayoub
quelle
2

Ich benutze Folgendes, weil ich denke, dass es am einfachsten zu lesen ist:

const elements = document.getElementsByClassName('element');
[...elements].forEach((element) => {
   // code
});

Brad
quelle
1

Nun, das funktioniert auch bei mir:

const elements = Object.values( document.querySelector(your selector here) )

Object.values()Rückgabe Arrayvon Werten eines bestimmten Objekts. NodeListist Objekt, wie alles in JS.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values

Aber es ist nicht kompatibel mit IE, also denke ich, Array.prototype.*array_method*.call(yourNodeList)ist die beste Option. Damit können Sie eine beliebige Array-Methode auf Ihrem Computer aufrufenNodeList

Rene Stefancik
quelle