Filtrar o mapear listas de nodos en ES6

7 minutos de lectura

¿Cuál es la forma más eficiente de filtrar o mapear una lista de nodos en ES6?

Según mis lecturas, usaría una de las siguientes opciones:

[...nodelist].filter

o

Array.from(nodelist).filter

¿Cuál recomendarías? ¿Y hay mejores formas, por ejemplo, sin involucrar matrices?

  • Básicamente, ambos métodos hacen lo mismo. lo que estas usando babeldespués [...coll] simplemente llamará Array.from(coll) para cualquier cosa que no sea un Array.

    – Leonid Beschastni

    24/09/2015 a las 15:36


  • por favor, ... la sintaxis puede no ser compatible con los IDE más antiguos mientras Array.from() es sólo un método regular.

    – Marat Tanalin

    24/09/2015 a las 17:01

  • [...nodelist] hará una matriz de un objeto si el objeto es iterable.
  • Array.from(nodelist) hará una matriz a partir de un objeto si el objeto es iterable o si el objeto es similar a una matriz (tiene .length y accesorios numéricos)

Tus dos ejemplos serán idénticos si NodeList.prototype[Symbol.iterator] existe, porque ambos casos cubren iterables. Si su entorno no ha sido configurado de tal manera que NodeList es iterable, sin embargo, su primer ejemplo fallará y el segundo tendrá éxito. Babel corrientemente no maneja este caso correctamente.

Entonces si tu NodeList es iterable, realmente depende de usted cuál usa. Probablemente elegiría caso por caso. Un beneficio de Array.from es que toma un segundo argumento de una función de mapeo, mientras que el primero [...iterable].map(item => item) tendría que crear una matriz temporal, Array.from(iterable, item => item) no lo haría Sin embargo, si no está mapeando la lista, no importa.

  • Solo ten en cuenta que Array.from no es compatible con IE.

    – Yann Dinendal

    15 de febrero de 2021 a las 10:50

  • @YannDìnendal Eso es cierto, pero esta pregunta se refiere a ES6, e IE no es compatible con ES6 en absoluto, por lo que ya es un callejón sin salida.

    – loganfsmyth

    16 de febrero de 2021 a las 21:07

  • Sí, es verdad. 🙂 Debí haber aclarado lo que quise decir: si confías en Babel para transpilar es6 a es5, no lo hará por defecto con los métodos de prototipo de polyfill. Así que sólo algo a tener en cuenta. 🙂

    – Yann Dinendal

    19 de febrero de 2021 a las 9:58

avatar de usuario
Sergiy Seletskyy

TL;RD;

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

El método slice() devuelve una matriz. Esa matriz devuelta es una copia superficial de la colección (NodeList)
Así que funciona más rápido que matriz.desde()

Así que funciona tan rápido como matriz.desde()

Los elementos de la colección original se copian en la matriz devuelta de la siguiente manera:

  • Para las referencias de objetos (y no el objeto real), el corte copia las referencias de objetos en la nueva matriz. Tanto la matriz original como la nueva se refieren al mismo objeto. Si un objeto al que se hace referencia cambia, los cambios son visibles tanto para las matrices nuevas como para las originales.
  • Para cadenas, números y valores booleanos (no objetos String, Number y Boolean), slice copia los valores en la nueva matriz. Los cambios en la cadena, el número o el booleano en una matriz no afectan a la otra matriz.

Breve explicación sobre los argumentos.

Array.prototype.slice(beginIndex, endIndex)

  • toma argumentos opcionales beginIndex y endIndex. Si no se proporcionan, los segmentos usan beginIndex == 0, por lo que extrae todos los elementos de la colección.

Array.prototype.slice.call(espacio de nombres, beginIndex, endIndex)

  • toma un objeto como primer argumento. Si usamos una colección como un objeto, literalmente significa que llamamos al método de división directamente desde ese objeto. espacio de nombres.slice()

  • Gracias por este fragmento de código, que podría proporcionar una ayuda limitada e inmediata. Una explicación adecuada mejoraría en gran medida su valor a largo plazo al mostrar por qué es una buena solución al problema y la haría más útil para futuros lectores con otras preguntas similares. Edite su respuesta para agregar alguna explicación, incluidas las suposiciones que ha hecho.

    – Maximiliano Peters

    13 abr 2018 a las 18:39

  • Me pregunto si esto tiene soporte para IE desde Array.from no es. Es hora de encontrar una máquina IE. Ahora estoy realmente confundido porque pude usar Array.from en IE10 e IE11:\. Este método funciona en IE10 + 11, pero Array. no me facilita el trabajo cuando toda la documentación dice lo contrario.

    – CTS_AE

    12 de julio de 2018 a las 19:22

  • Array.from no me funciona en IE11 El objeto no admite la propiedad o el método ‘desde’

    – Fus Ro Dah

    09/08/2018 a las 20:59

  • Gracias, esto funcionó para mí en una implementación anterior de JavaScript

    – Vic Seedoubleyew

    5 mayo 2019 a las 17:20

  • Array.from también devuelve una copia superficial. Así que no veo cómo tú concluir que funciona más rápido que Array#slice.

    – Roberto

    28 de junio de 2020 a las 11:05


Encontre un referencia que usa map directamente en NodeList por

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

No lo he probado, pero parece plausible que esto sea más rápido porque debería acceder directamente a NodeList.

Qué tal esto:

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

Es el mismo enfoque que se menciona en los documentos de MDN para NodeList.forEach (bajo ‘Polyfill’), funciona para IE11borde, cromo y FF.

Filtrar o mapear listas de nodos en ES6

Salí de esta simple función. @ver https://developer.mozilla.org/fr/docs/Web/API/NodeList/entries#exemple

function filterNodeList(NodeList, callback) {
if (!typeof callback === "function") callback = (i) => i; // Any have better idear?

const Result = document.createElement("div");
//# No need to filter empty NodeList
if (Node.length === 0) return Node;

for (let i = 0; i < Node.length; i++) {
  if (callback(Node.item(i))) Result.appendChild(Node.item(i));
}

return Result.childNodes;}

Estoy dispuesto a aprender más :>

  • Para eliminar los elementos del DOM, puede clonarlos y eliminar las referencias Result.appendChild(NodeList.item(i).cloneNode). Luego, antes de trabajar en ellos, solo tiene que regresar y decir dom, dame este tipo de nodo con este atributo :: ¡Importante! Nodo === Lista de nodos….

    – FATCHOLA

    29 de julio de 2021 a las 19:32


avatar de usuario
jave.web

[...a].filter contra Array.from(a).filter

No es una diferencia “real” en el rendimiento, Array.from podría ser un poquito más rápido porque no estás creando un nuevo Array en el “nivel JS”, pero sucede directamente en el código nativo.

Rendimiento – considere no usando o

Sin embargo para actuación (y también para evitar “Array-ing”) debes considerar por qué ¿Estás filtrando un NodeList y donde como lo obtuviste. En muchos casos, solo desea un elemento en particular ya sea por id o por class u otro selector de CSS.

document.querySelectorAll es como 10x – 200x más rápido y funciona para cualquier selector de CSS

document.getElementById es aún más rápido (pero por supuesto requiere un id)

Incluso puedes optimizar querySelectorAll u omita el caso “todavía no conocido” si proporciona un padre prealmacenado para buscar, déjeme darle un ejemplo:

let mainbar = document.getElementById('mainbar');
mainbar.querySelectorAll('.flex--item');

es casi 10 veces más rápido que

Array.from(a).filter(el => el.classList.contains("flex--item"))

También tenga en cuenta que document.querySelectorAll('#mainbar .flex--item'); sigue siendo aproximadamente 5 veces más rápido que Array filtrado, pero aproximadamente 2 veces más lento que almacenar previamente el padre con un id.

Además de un mejor rendimiento, usted también siempre obtendrá NodeList (Puede que esté vacío, pero seguirá estando NodeList) y eso vale para ambos document.querySelectorAll() y Element.querySelectorAll()

  • Para eliminar los elementos del DOM, puede clonarlos y eliminar las referencias Result.appendChild(NodeList.item(i).cloneNode). Luego, antes de trabajar en ellos, solo tiene que regresar y decir dom, dame este tipo de nodo con este atributo :: ¡Importante! Nodo === Lista de nodos….

    – FATCHOLA

    29 de julio de 2021 a las 19:32


avatar de usuario
realmag777

Usando ECMAS 2016:

let nodes = [...document.querySelector('__SELECTOR__').childNodes].filter(item => item.nodeType === 1);

¿Ha sido útil esta solución?