Filtruj lub mapuj listy węzłów w ES6

87

Jaki jest najbardziej skuteczny sposób filtrowania lub mapowania listy węzłów w ES6?

W oparciu o moje odczyty użyłbym jednej z następujących opcji:

[...nodelist].filter

lub

Array.from(nodelist).filter

Który byś polecił? Czy są lepsze sposoby, na przykład bez użycia tablic?

Christophe
źródło
2
Zasadniczo obie metody robią to samo. Jeśli używasz babel, po [...coll]prostu wywoła Array.from(coll)wszystko, co nie jest plikiem Array.
Leonid Beschastny
FWIW, ...składnia może nie być obsługiwana przez starsze IDE, chociaż Array.from()jest to zwykła metoda.
Marat Tanalin

Odpowiedzi:

126
  • [...nodelist] utworzy tablicę z obiektu, jeśli obiekt jest iterowalny.
  • Array.from(nodelist)utworzy tablicę z obiektu, jeśli obiekt jest iterowalny lub jeśli obiekt jest podobny do tablicy (ma .lengthi numeryczne właściwości)

Twoje dwa przykłady będą identyczne, jeśli NodeList.prototype[Symbol.iterator]istnieją, ponieważ oba przypadki obejmują iterowalne. Jeśli jednak środowisko nie zostało skonfigurowane w sposób umożliwiający NodeListiterację, pierwszy przykład zakończy się niepowodzeniem, a drugi powiedzie się. Babelobecnie nie obsługuje prawidłowo tej sprawy .

Więc jeśli twój NodeListjest iterowalny, to naprawdę zależy od ciebie, którego użyjesz. Prawdopodobnie wybrałbym indywidualnie dla każdego przypadku. Jedną z korzyści Array.fromjest to, że pobiera drugi argument funkcji odwzorowującej, podczas gdy pierwszy [...iterable].map(item => item)musiałby utworzyć tymczasową tablicę, Array.from(iterable, item => item)co nie. Jeśli jednak nie mapujesz listy, nie ma to znaczenia.

loganfsmyth
źródło
17

TL; DR;

Array.prototype.slice.call(nodelist).filter

Metoda slice () zwraca tablicę. Ta zwrócona tablica jest płytką kopią kolekcji (NodeList), więc działa szybciej niż Array.from () Więc działa tak szybko jak Array.from ()

Elementy oryginalnej kolekcji są kopiowane do zwracanej tablicy w następujący sposób:

  • W przypadku odniesień do obiektów (a nie rzeczywistego obiektu) wycinek kopiuje odniesienia do obiektów do nowej tablicy. Zarówno oryginalna, jak i nowa tablica odnoszą się do tego samego obiektu. Jeśli obiekt, do którego istnieje odniesienie, ulegnie zmianie, zmiany będą widoczne zarówno dla nowej, jak i oryginalnej tablicy.
  • W przypadku łańcuchów, liczb i wartości logicznych (nie obiektów typu String, Number i Boolean) wycinek kopiuje wartości do nowej tablicy. Zmiany ciągu, liczby lub wartości logicznej w jednej tablicy nie wpływają na drugą tablicę.

Krótkie wyjaśnienie dotyczące argumentów

Array.prototype.slice (beginIndex, endIndex)

  • przyjmuje opcjonalne argumenty beginIndex i endIndex. Jeśli ich nie podano, plasterki używa beginIndex == 0, więc wyodrębnia wszystkie elementy z kolekcji

Array.prototype.slice.call (namespace, beginIndex, endIndex)

  • przyjmuje obiekt jako pierwszy argument. Jeśli używamy kolekcji jako obiektu, dosłownie oznacza to, że wywołujemy metodę slice bezpośrednio z tego obiektu namespace.slice ()
Serge Seletskyy
źródło
2
Dziękujemy za ten fragment kodu, który może zapewnić ograniczoną, natychmiastową pomoc. Właściwe wyjaśnienie znacznie poprawiłoby jego długoterminową wartość, pokazując, dlaczego jest to dobre rozwiązanie problemu i uczyniłoby go bardziej użytecznym dla przyszłych czytelników z innymi, podobnymi pytaniami. Zmień swoją odpowiedź, dodając wyjaśnienie, w tym przyjęte założenia.
Maximilian Peters
Zastanawiam się, czy to ma obsługę IE, ponieważ Array.fromnie. Czas znaleźć maszynę IE. Teraz jestem naprawdę zdezorientowany, ponieważ mogłem używać Array.from w IE10 i IE11: \. Ta metoda działa w IE10 + 11, ale Array nie ułatwia mi pracy, gdy cała dokumentacja mówi inaczej.
CTS_AE
Array.fromnie działa dla mnie w IE11 Obiekt nie obsługuje właściwości lub metody „od”
Fus Ro Dah
Dzięki, zadziałało to dla mnie przy starej implementacji JavaScript
Vic Seedoubleyew
1
Array.fromzwraca również skróconą kopię. Więc nie rozumiem, jak można dojść do wniosku , że działa szybciej niż Array#slice.
Robert
9

Znalazłem odniesienie, które używa mapbezpośrednio w NodeList przez

Array.prototype.map.call(nodelist, fn)

Nie testowałem tego, ale wydaje się prawdopodobne, że będzie to szybsze, ponieważ powinno uzyskać bezpośredni dostęp do NodeList.

goweon
źródło
2

Co powiesz na to:

// Be evil. Extend the prototype.
if (window.NodeList && !NodeList.prototype.filter) {
  NodeList.prototype.filter = Array.prototype.filter;
}

// Use it like you'd expect:
const noClasses = document
  .querySelectorAll('div')
  .filter(div => div.classList.length === 0)

Jest to takie samo podejście, jak wspomniano w dokumentacji MDN dla NodeList.forEach (w sekcji „Polyfill”), działa dla IE11 , Edge, Chrome i FF.

panepeter
źródło