javascript - node - queryselectorall to array
¿La forma más rápida de convertir JavaScript NodeList a Array? (13)
Las preguntas respondidas anteriormente aquí dijeron que esta era la forma más rápida:
//nl is a NodeList
var arr = Array.prototype.slice.call(nl);
Al hacer una evaluación comparativa en mi navegador, descubrí que es más de 3 veces más lento que esto:
var arr = [];
for(var i = 0, n; n = nl[i]; ++i) arr.push(n);
Ambos producen el mismo resultado, pero me cuesta creer que mi segunda versión sea la forma más rápida posible, especialmente porque la gente ha dicho lo contrario aquí.
¿Es esta una peculiaridad en mi navegador (Chromium 6)? ¿O hay una manera más rápida?
EDITAR: Para cualquier persona que se preocupe, me decidí por lo siguiente (que parece ser el más rápido en todos los navegadores que probé):
//nl is a NodeList
var l = []; // Will hold the array of Node''s
for(var i = 0, ll = nl.length; i != ll; l.push(nl[i++]));
EDIT2: encontré una forma aún más rápida
// nl is the nodelist
var arr = [];
for(var i = nl.length; i--; arr.unshift(nl[i]));
Una forma sencilla de convertir objetos de tipo matriz en una matriz
nodeList = Array.from(document.querySelectorAll(''li''))
// Checking if it''s array
Array.isArray(nodeList) // true
Algunas optimizaciones:
- guardar la longitud de NodeList en una variable
- establecer explícitamente la longitud de la nueva matriz antes de establecer.
- Accede a los índices, en lugar de empujar o cambiar.
Código ( jsPerf ):
var arr = [];
for (var i = 0, ref = arr.length = nl.length; i < ref; i++) {
arr[i] = nl[i];
}
Aquí hay una nueva manera fresca de hacerlo usando el operador de propagación ES6 :
let arr = [...nl];
Con ES6, ahora tenemos una forma sencilla de crear un Array desde una NodeList: la función Array.from()
.
// nl is a NodeList
let myArray = Array.from(nl)
Echa un vistazo a esta entrada de blog here que habla de lo mismo. De lo que deduzco, el tiempo adicional podría tener que ver con subir la cadena de alcance.
El navegador más rápido y cruzado es
for(var i=-1,l=nl.length;++i!==l;arr[i]=nl[i]);
Como he comparado en
http://jsbin.com/oqeda/98/edit
* Gracias @CMS por la idea!
El segundo tiende a ser más rápido en algunos navegadores, pero el punto principal es que tiene que usarlo porque el primero no es el navegador cruzado. A pesar de que los tiempos están cambiando
@kangax ( vista previa de IE 9 )
Array.prototype.slice ahora puede convertir ciertos objetos del host (por ejemplo, NodeList) en arreglos, algo que la mayoría de los navegadores modernos han podido hacer durante bastante tiempo.
Ejemplo:
Array.prototype.slice.call(document.childNodes);
Esta es la función que uso en mi JS:
function toArray(nl) {
for(var a=[], l=nl.length; l--; a[l]=nl[l]);
return a;
}
Estos son los cuadros actualizados a partir de la fecha de esta publicación (el cuadro de "plataforma desconocida" es Internet Explorer 11.15.16299.0):
A partir de estos resultados, parece que el método de preasignación 1 es la apuesta más segura entre navegadores.
Los resultados dependerán completamente del navegador, para dar un veredicto objetivo, tenemos que hacer algunas pruebas de rendimiento, aquí hay algunos resultados, puede ejecutarlos here :
Chrome 6:
Firefox 3.6:
Firefox 4.0b2:
Safari 5:
Vista previa de la plataforma IE9 3:
Más rápido y más corto:
// nl is the nodelist
var a=[], l=nl.length>>>0;
for( ; l--; a[l]=nl[l] );
Simplemente ser un completista aquí, y estos son rápidos de escribir:
let arr1 = Array.prototype.filter.call(nl, n => true);
let arr2 = Array.prototype.map.call(nl, n => n);
NodeList.prototype.forEach = Array.prototype.forEach;
Ahora puede hacer document.querySelectorAll (''div''). ForEach (function () ...)