Jaki jest najlepszy sposób konwersji NodeList na tablicę w JavaScript?


84

Metoda DOM document.querySelectorAll()(i kilka innych) zwraca plik NodeList.

Aby operować na liście, np. Używając forEach(), NodeListnależy najpierw przekonwertować plik Array.

Jaki jest najlepszy sposób konwertowania NodeListpliku na Array?


1
Myślę, że wartość zwracana przez querySelectorAll () jest technicznie nazywana NodeList.
jfriend00

from mdm "elementList = document.querySelectorAll (selektory);"
cc młody

1
elementList to nazwa zmiennej. Ta sama strona opisuje, w jaki sposób typ zwracanej wartości jest NodeList.
jfriend00

dzięki za korektę - poprawione w pytaniu
cc młody

Odpowiedzi:


70

Dzięki ES6 możesz po prostu:

const spanList = [...document.querySelectorAll("span")];

1
To daje miType 'NodeListOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
oddzwonienie

Cześć @callback, wygląda to na błąd związany z TypeScript. Być może wybrałeś docelową kompilację es6 bez dodawania "es6" do tablicy lib twojego pliku tsconfig. Pozdrawiam
Freezystem

1
Cześć @Freezystem, masz rację! Celuję w es2015. Dzięki!
oddzwonienie

@callback ES6 i ES2015 to to samo
DarkNeuron

66

Z ES6 możesz korzystać Array.from(myNodeList). Następnie użyj swojej ulubionej metody tablicowej.

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

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

Użyj podkładki ES6, aby to działało również w starszych przeglądarkach.


Jeśli używasz transpilera (na przykład Babel), są jeszcze dwie alternatywy:

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);
});

nie jest również prawdą w ramach es6, że nodeList dostarcza iterator?
cc młody

4
@ccyoung, ale iterator nie działa w niezgodnych przeglądarkach ES6, ponieważ nie można podkładać obiektu Symbol, więc lepiej jest go używać, Array.from(myNodeList)ponieważ można go podłożyć.
Roc

więc mam ten problem, w którym Array.from (el.childNodes) nie zwraca pierwszego węzła jako część tablicy.
zinoadidi

49

Możesz przekonwertować go na tablicę używając slicemetody z Arrayprototypu:

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

Ponadto, jeśli wszystko, czego potrzebujesz forEach, to możesz wywołać to z Arrayprototypu, bez uprzedniego przekształcania go w tablicę:

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

W ES6 możesz użyć nowej Array.fromfunkcji, aby przekonwertować ją na tablicę:

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

Jest to obecnie dostępne tylko w przeglądarkach krwawiących krawędzi, ale jeśli korzystasz z usługi polyfill , będziesz mieć dostęp do tej funkcji na całej planszy.


Jeśli używasz transpilera ES6 , możesz for..ofzamiast tego użyć pętli:

for (var element of document.querySelectorAll('.some .elements')) {
  // use element here
}

dzięki. pod nowszymi myślami javascript / mając nadzieję, że był bardziej zwięzły przymus.
cc młody

6
@cc young - zwróć uwagę, powodem, dla którego używam Array.prototype.forEachzamiast tego [].forEach, jest to, że ten ostatni tworzy nowy obiekt Array, który jest całkowicie niepotrzebny.
Joseph Silber,

@JosephSilber ahh dziękuję - czy nowa utworzona tablica jest pusta []? Uważam, że zbierze śmieci, a wpływ na pamięć jest znikomy, czy ktoś może to skomentować?
Daniel Sokolowski

@Daniel to prawda, ale nadal istnieje obliczenia tworzenia i niszczenia tablicy.
Brett

21

Dlaczego warto konwertować? - po prostu callfunkcja Array bezpośrednio na kolekcji elementów;)

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

zakładając oczywiście, że $ jest twoim aliasem dla querySelectorAll


edycja: ES6 pozwala na jeszcze krótszą składnię [...$('a')]( działa tylko w Firefoksie, od maja 2014 )


Zakładając, że $tak querySelectorAll.
c69

3
Twoja odpowiedź sugeruje użycie jQuery. Jeśli tak jest, to dzięki .each().
Matt Ball,

1
lol dlaczego ? nic nie zabrania ci tworzenia aliasów typu function $ ( s ) { return document.querySelectorAll(s); }.
c69

5
Jeśli masz zamiar używać jQuery, to bardziej prostym rozwiązaniem jest:$('a').each(function(i, v) {...});
jfriend00

2
offtopic: EcmaScript 5 jest standardem już od roku, wszystkie przeglądarki obecnej generacji obsługują nowe metody tablic, a pytanie dotyczyło w szczególności używania tych metod w NodeList, czyli zbieraniu elementów.
c69

10

Aktualizacja 2020: nodeList.forEach () jest teraz oficjalnym standardem i jest obsługiwany we wszystkich obecnych przeglądarkach.

Starsze przeglądarki mogą używać poniższego wypełnienia.

Aby operować na liście w javascript, np. Używając forEach (), NodeList musi zostać przekonwertowana na Array.

To nieprawda. .forEach()działa w obecnych przeglądarkach. Jeśli go brakuje, możesz użyć polyfill, aby dodać .forEach () z Array do NodeList i działa dobrze:

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

Możesz teraz biegać:

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

Aby iterować po NodeLists, tak jak Arrays.

Daje to znacznie krótszy i czystszy kod niż .call () wszędzie.


1
Ta odpowiedź była dokładnie tym, czego potrzebowałem, a te 3 wiersze zaoszczędziły dużo czasu. Wszystkie inne odpowiedzi wymagałyby zmiany części kodu i nie rozumiem dlaczego.
Scribblemacher

głosy negatywne były prawdopodobnie spowodowane tym, że małpa łatanie wbudowanych prototypów jest uważane za złą praktykę
DuBistKomisch

@DuBistKomisch To jest wypełnienie, stosowane tylko wtedy, gdy nie istnieje standardowa lista NodeList.foreach ().
mikemaccana

2
ach mój zły, nie zdawałem sobie sprawy, że faktycznie dodali forEachkonkretnie, przyjechałem tutaj w poszukiwaniufilter
DuBistKomisch

@DuBistKomisch możesz użyć tej samej techniki filter, ale możesz chcieć nadać mu nieoficjalną nazwę NodeList.prototype.dbkFilterlub podobną, jeśli martwisz się o przyszły standard korzystający z innej implementacji.
mikemaccana

9

Czy to musi być forEach? Możesz po prostu użyć forpętli do iteracji po liście:

for (var i = 0; i < elementList.length; i++) {
    doSomethingWith(elementlist.item(i));
}

1
+1 za przejście z prostym rozwiązaniem, które nie dodaje niepotrzebnych konwersji tablic. FYI, zamiast elementList.item(i), możesz po prostu użyć elementList[i].
jfriend00

4
osobiście znajduję forEach()lepszy styl programowania i mniej rozwlekły
cc young

@cc young: Właściwie zgadzam się z tobą. Z wyjątkiem takich przypadków, w których musiałbym przeprowadzić konwersję, aby móc użyć mojego ulubionego wzorca. To sprawia, że ​​jest niezgrabny i wygląda następująco: „Kiedy masz tylko młotek, wszystko zaczyna wyglądać jak gwóźdź”.
nfechner

A oto bardziej zwariowany sposób :)for (var oElement, i = 0; oElement = aMenuItemsElements; i++ { console.log(oElement); }
Daniel Sokolowski

Problem polega na tym, że nie można zagnieździć kolejnej for (var i…)pętli, ponieważ pętla for nie tworzy własnego zakresu (tak jak teraz robi to w C / C ++). A potem isię pomieszali.
Jens

2

ES6 pozwala na fajne sposoby, takie jak, var nodeArray = Array.from(nodeList)ale moim ulubionym jest nowy operator rozprzestrzeniania.

var nodeArray = Array(...nodeList);

Idealne rozwiązanie! To rozwiązanie dotyczy również maszynopisu.
Nirus

Chciałbym dodać, że działa to tylko z TypeScript, o ile nie transpilujesz do ES5 lub niższego.
Rudey

2

To zadziałało ze mną w ES6

załóżmy, że masz taką listę węzłów

<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);

2

Używam następujących, ponieważ wydaje mi się, że najłatwiej jest to przeczytać:

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


2

Cóż, to działa również dla mnie:

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

Object.values()zwraca Arraywartości danego obiektu. NodeListjest obiektem, tak jak wszystko w JS.

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

Ale nie jest kompatybilny z IE, więc myślę, że Array.prototype.*array_method*.call(yourNodeList)jest to najlepsza opcja. Dzięki temu możesz wywołać dowolną metodę tablicową na swoimNodeList


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.