Filtrare o mappare gli elenchi dei nodi in ES6


90

Qual è il modo più efficiente per filtrare o mappare un elenco dei nodi in ES6?

In base alle mie letture, utilizzerei una delle seguenti opzioni:

[...nodelist].filter

o

Array.from(nodelist).filter

Quale consiglieresti? E ci sono modi migliori, ad esempio senza coinvolgere gli array?


2
Fondamentalmente, entrambi i metodi fanno la stessa cosa. Se stai usando babel, [...coll]chiamerà semplicemente Array.from(coll)tutto ciò che non è un file Array.
Leonid Beschastny

FWIW, la ...sintassi potrebbe non essere supportata dai vecchi IDE mentre Array.from()è solo un metodo normale.
Marat Tanalin

Risposte:


131
  • [...nodelist] creerà un array di un oggetto se l'oggetto è iterabile.
  • Array.from(nodelist)creerà un array da un oggetto se l'oggetto è iterabile o se l'oggetto è simile a un array (ha .lengthe oggetti di scena numerici)

I tuoi due esempi saranno identici se NodeList.prototype[Symbol.iterator]esistono, perché entrambi i casi coprono gli iterabili. Se il tuo ambiente non è stato configurato in modo tale da NodeListessere iterabile, il tuo primo esempio fallirà e il secondo avrà esito positivo. Babelattualmente non gestisce correttamente questo caso .

Quindi, se il tuo NodeListè iterabile, dipende da te quale utilizzare. Probabilmente sceglierei caso per caso. Un vantaggio di Array.fromè che richiede un secondo argomento di una funzione di mappatura, mentre il primo [...iterable].map(item => item)dovrebbe creare un array temporaneo, Array.from(iterable, item => item)no. Se non stai mappando l'elenco, tuttavia, non importa.


17

TL; DR;

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

Il metodo slice () restituisce un array. L'array restituito è una copia superficiale della raccolta (NodeList) Quindi funziona più velocemente di Array.from () Quindi funziona velocemente come Array.from ()

Gli elementi della raccolta originale vengono copiati nell'array restituito come segue:

  • Per i riferimenti agli oggetti (e non all'oggetto reale), slice copia i riferimenti agli oggetti nel nuovo array. Sia la matrice originale che quella nuova fanno riferimento allo stesso oggetto. Se un oggetto referenziato cambia, le modifiche sono visibili sia per la matrice nuova che per quella originale.
  • Per stringhe, numeri e booleani (non oggetti String, Number e Boolean), slice copia i valori nel nuovo array. Le modifiche alla stringa, al numero o al valore booleano in un array non influiscono sull'altro array.

Breve spiegazione sugli argomenti

Array.prototype.slice (beginIndex, endIndex)

  • accetta gli argomenti facoltativi beginIndex e endIndex. Se non vengono fornite sezioni, utilizza beginIndex == 0, quindi estrae tutti gli elementi dalla raccolta

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

  • accetta un oggetto come primo argomento. Se usiamo una collezione come oggetto, significa letteralmente che chiamiamo il metodo slice direttamente dallo spazio dei nomi di quell'oggetto .

2
Grazie per questo snippet di codice, che potrebbe fornire un aiuto limitato e immediato. Una spiegazione adeguata migliorerebbe notevolmente il suo valore a lungo termine mostrando perché questa è una buona soluzione al problema e la renderebbe più utile per i futuri lettori con altre domande simili. Modifica la tua risposta per aggiungere qualche spiegazione, comprese le ipotesi che hai fatto.
Maximilian Peters

Mi chiedo se questo ha il supporto di IE poiché Array.fromnon lo fa. È ora di trovare una macchina IE. Ora sono davvero confuso perché sono stato in grado di utilizzare Array.from in IE10 e IE11: \. Questo metodo funziona in IE10 + 11 ma non sono facilitato dal lavoro di Array.from quando tutta la documentazione dice diversamente.
CTS_AE

Array.fromnon funziona per me in IE11 L' oggetto non supporta la proprietà o il metodo "da"
Fus Ro Dah

Grazie, questo ha funzionato per me su una vecchia implementazione di JavaScript
Vic Seedoubleyew

1
Array.fromrestituisce anche una copia superficiale. Quindi non vedo come concludi che funziona più velocemente di Array#slice.
Robert

9

Ho trovato un riferimento che utilizza mapdirettamente su NodeList di

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

Non l'ho testato, ma sembra plausibile che sia più veloce perché dovrebbe accedere direttamente a NodeList.


4

Cosa ne pensi di questo:

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

È lo stesso approccio menzionato nei documenti MDN per NodeList.forEach (sotto "Polyfill"), funziona per IE11 , Edge, Chrome e FF.


leggero avvertimento, ora nodeList.filter ti darà un array invece di un elenco di nodi. non dovrebbe essere un problema, ma facile da dimenticare ^^
hanshenrik
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.