Filtrer ou mapper les listes de nœuds dans ES6


87

Quelle est la manière la plus efficace de filtrer ou de mapper une liste de nœuds dans ES6?

Sur la base de mes lectures, j'utiliserais l'une des options suivantes:

[...nodelist].filter

ou

Array.from(nodelist).filter

Lequel recommanderiez-vous? Et y a-t-il de meilleures façons, par exemple, sans impliquer de tableaux?


2
Fondamentalement, les deux méthodes font la même chose. Celui que vous utilisez babel, [...coll]appellera alors simplement tout Array.from(coll)ce qui n'est pas un fichier Array.
Leonid Beschastny

FWIW, la ...syntaxe peut ne pas être prise en charge par les IDE plus anciens alors qu'elle Array.from()n'est qu'une méthode classique.
Marat Tanalin

Réponses:


126
  • [...nodelist] fera un tableau à partir d'un objet si l'objet est itérable.
  • Array.from(nodelist)fera un tableau à partir d'un objet si l'objet est itérable ou si l'objet est semblable à un tableau (a .lengthet accessoires numériques)

Vos deux exemples seront identiques s'ils NodeList.prototype[Symbol.iterator]existent, car les deux cas couvrent les itérables. Si votre environnement n'a pas été configuré de manière à être NodeListitérable, votre premier exemple échouera et le second réussira. Babelactuellement ne gère pas correctement ce cas .

Donc, si votre NodeListest itérable, c'est vraiment à vous que vous l'utilisez. Je choisirais probablement au cas par cas. L'un des avantages de Array.fromest qu'il prend un deuxième argument d'une fonction de mappage, alors que le premier [...iterable].map(item => item)devrait créer un tableau temporaire, Array.from(iterable, item => item)non. Cependant, si vous ne mappez pas la liste, cela n'a pas d'importance.


17

TL, DR;

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

La méthode slice () renvoie un tableau. Ce tableau retourné est une copie superficielle de la collection (NodeList) Donc il fonctionne plus vite que Array.from () Donc ça marche aussi vite que Array.from ()

Les éléments de la collection d'origine sont copiés dans le tableau renvoyé comme suit:

  • Pour les références d'objet (et non l'objet réel), slice copie les références d'objet dans le nouveau tableau. Le tableau d'origine et le nouveau tableau font tous deux référence au même objet. Si un objet référencé change, les modifications sont visibles à la fois pour les tableaux nouveaux et d'origine.
  • Pour les chaînes, les nombres et les booléens (et non les objets String, Number et Boolean), slice copie les valeurs dans le nouveau tableau. Les modifications apportées à la chaîne, au nombre ou au booléen dans un tableau n'affectent pas l'autre tableau.

Brève explication des arguments

Array.prototype.slice (beginIndex, endIndex)

  • prend les arguments facultatifs beginIndex et endIndex. S'ils ne sont pas fournis, les tranches utilisent beginIndex == 0, donc il extrait tous les éléments de la collection

Array.prototype.slice.call (espace de noms, beginIndex, endIndex)

  • prend un objet comme premier argument. Si nous utilisons une collection comme objet, cela signifie littéralement que nous appelons la méthode slice directement à partir de cet objet namespace.slice ()

2
Merci pour cet extrait de code, qui pourrait fournir une aide limitée et immédiate. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi c'est une bonne solution au problème et la rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez formulées.
Maximilian Peters

Je me demande si cela n'a pas de support IE depuis Array.from. Il est temps de trouver une machine IE. Maintenant, je suis vraiment confus car j'ai pu utiliser Array.from dans IE10 et IE11: \. Cette méthode fonctionne dans IE10 + 11, mais Array.fr ne me facilite pas la tâche lorsque toute la documentation dit le contraire.
CTS_AE

Array.fromne fonctionne pas pour moi dans IE11 L' objet ne prend pas en charge la propriété ou la méthode 'from'
Fus Ro Dah

Merci, cela a fonctionné pour moi sur une ancienne implémentation de JavaScript
Vic Seedoubleyew

1
Array.fromrenvoie également une copie superficielle. Donc je ne vois pas comment vous concluez que cela fonctionne plus vite que Array#slice.
Robert

9

J'ai trouvé une référence qui utilise mapdirectement sur la NodeList par

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

Je ne l'ai pas testé, mais il semble plausible que ce soit plus rapide car il devrait accéder directement à la NodeList.


2

Que dis-tu de ça:

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

C'est la même approche que celle mentionnée dans la documentation MDN pour NodeList.forEach (sous 'Polyfill'), cela fonctionne pour IE11 , Edge, Chrome et FF.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.