son - recorrer elementos dom javascript
¿Cuál es la mejor manera de recorrer un conjunto de elementos en JavaScript? (15)
En el pasado y con la mayoría de mis proyectos actuales, suelo usar un ciclo for como este:
var elements = document.getElementsByTagName(''div'');
for (var i=0; i<elements.length; i++) {
doSomething(elements[i]);
}
He escuchado que usar un ciclo "reverse while" es más rápido, pero no tengo una forma real de confirmar esto:
var elements = document.getElementsByTagName(''div''),
length = elements.length;
while(length--) {
doSomething(elements[length]);
}
¿Qué se considera una mejor práctica cuando se trata de crear un bucle en los elementos de JavaScript o cualquier matriz para ese caso?
A riesgo de que me gritaran, obtendría una biblioteca de ayuda de JavaScript como jquery o prototipo que encapsulan la lógica en buenos métodos; ambos tienen un método / iterador para hacerlo, y ambos se esfuerzan para que sea compatible con varios navegadores.
EDITAR: Esta respuesta se publicó en 2008. Hoy en día existen construcciones mucho mejores. Este caso particular se resolvería con .forEach
.
Aquí hay una buena forma de bucle que suelo usar. Usted crea la variable iterada a partir de la instrucción for y no necesita verificar la propiedad length, que puede ser costosa especialmente al iterar a través de una NodeList. Sin embargo, debe tener cuidado , no puede usarlo si alguno de los valores en el conjunto puede ser "falso" . En la práctica, solo lo uso cuando itero sobre una matriz de objetos que no contiene nulos (como una NodeList). Pero me encanta su azúcar sintáctica.
var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];
for (var i=0, item; item = list[i]; i++) {
// Look no need to do list[i] in the body of the loop
console.log("Looping: index ", i, "item" + item);
}
Tenga en cuenta que esto también se puede usar para retroceder (siempre que su lista no tenga una propiedad [''-1'']
)
var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];
for (var i = list.length - 1, item; item = list[i]; i--) {
console.log("Looping: index ", i, "item", item);
}
Creo que tienes dos alternativas. Para los elementos dom como jQuery y frameworks similares, obtienes un buen método de iteración. El segundo enfoque es el ciclo for.
Creo que usar la primera forma es probablemente el camino a seguir, ya que es probablemente la estructura de bucle más común en el universo conocido, y dado que no creo que el bucle inverso te ahorre tiempo en la realidad (sigue haciendo un incremento / decremento y una comparación en cada iteración).
El código que es reconocible y legible para los demás definitivamente es algo bueno.
La forma de bucle proporcionada por Juan Mendez es muy útil y práctica, la cambié un poco, por lo que ahora funciona con cadenas falsas, nulas, nulas y vacías también.
var items = [
true,
false,
null,
0,
""
];
for(var i = 0, item; (item = items[i]) !== undefined; i++)
{
console.log("Index: " + i + "; Value: " + item);
}
Me gusta hacer:
var menu = document.getElementsByTagName(''div'');
for (var i = 0; menu[i]; i++) {
...
}
No hay llamadas a la longitud de la matriz en cada iteración.
Me gusta usar un TreeWalker si el conjunto de elementos es TreeWalker de un nodo raíz.
Prefiero el ciclo for porque es más legible. El bucle de longitud a 0 sería más eficiente que el bucle de 0 a la longitud. Y usar un ciclo while invertido es más eficiente que un ciclo foor como dijiste. Ya no tengo el enlace a la página con resultados de comparación, pero recuerdo que la diferencia varió en los diferentes navegadores. Para algunos navegadores, el ciclo while invertido era el doble de rápido. Sin embargo, no importa si está haciendo un bucle de arreglos "pequeños". En su caso de ejemplo, la longitud de los elementos será "pequeña"
Sé que esta pregunta es antigua, pero aquí hay otra solución extremadamente simple ...
var elements = Array.from(document.querySelectorAll("div"));
Entonces se puede usar como cualquier arreglo estándar.
Sé que no quiere escuchar eso, pero considero que la mejor práctica es la más legible en este caso. Mientras el ciclo no cuente desde aquí hasta la luna, la ganancia de rendimiento no será suficiente.
También puede consultar esta página en mi sitio donde comparo la velocidad de un bucle incremental for
, un bucle invertido do/while
while y el dispositivo Duff.
También vea mi comentario sobre la prueba de Andrew Hedges ...
Intenté ejecutar una prueba para comparar una iteración simple, la optimización que introduje y la inversa do / while, donde los elementos de una matriz se probaron en cada ciclo.
Y, por desgracia, no es de extrañar, los tres buscadores que probé tuvieron resultados muy diferentes, ¡aunque la iteración simple optimizada fue la más rápida en todos! -)
Prueba:
Una matriz con 500,000 elementos construidos fuera de la prueba real, para cada iteración se revela el valor del elemento de matriz específico.
Prueba de ejecución 10 veces.
IE6:
Resultados:
Simple: 984,922,937,984,891,907,906,891,906,906
Promedio: 923.40 ms.
Optimizado: 766,766,844,797,750,750,765,765,766,766
Promedio: 773.50 ms.
Reverse do / while: 3375,1328,1516,1344,1375,1406,1688,1344,1297,1265
Promedio: 1593.80 ms. (Note un resultado especialmente incómodo)
Opera 9.52:
Resultados:
Simple: 344,343,344,359,343,359,344,359,359,359
Promedio: 351,30 ms.
Optimizado: 281,297,297,297,297,281,281,297,281,281
Promedio: 289.00 ms
Reverse do / while: 391,407,391,391,500,407,407,406,406,406
Promedio: 411,20 ms.
FireFox 3.0.1:
Resultados:
Simple: 278,251,259,245,243,242,259,246,247,256
Promedio: 252.60 ms.
Optimizado: 267,222,223,226,223,230,221,231,224,230
Promedio: 229.70 ms.
Reverse do / while: 414,381,389,383,388,389,381,387,400,379
Promedio: 389,10 ms.
Tenga en cuenta que, en algunos casos, debe realizar un ciclo en orden inverso (pero también puede usar i--).
Por ejemplo, alguien quería usar la nueva función getElementsByClassName
para hacer un bucle en elementos de una clase determinada y cambiar esta clase. Descubrió que solo se cambiaba uno de los dos elementos (en FF3).
Esto se debe a que la función devuelve Live NodeList, que refleja los cambios en el árbol Dom. Caminar la lista en orden inverso evitó este problema.
var menus = document.getElementsByClassName("style2");
for (var i = menus.length - 1; i >= 0; i--)
{
menus[i].className = "style1";
}
Al aumentar la progresión del índice, cuando le preguntamos al índice 1, FF inspecciona el Dom y omite el primer elemento con style2, que es el 2º del Dom original, ¡así devuelve el tercer elemento inicial!
Tuve un problema muy similar anteriormente con document.getElementsByClassName (). No sabía lo que era una lista de nodos en ese momento.
var elements = document.getElementsByTagName(''div'');
for (var i=0; i<elements.length; i++) {
doSomething(elements[i]);
}
Mi problema era que esperaba que los elementos fueran una matriz, pero no es así. La lista de nodos Document.getElementsByTagName () returns es iterable, pero no puede llamar a los métodos array.prototype en él.
Sin embargo, puede llenar una matriz con elementos de la lista de nodos como este:
var myElements = [];
for (var i=0; i<myNodeList.length; i++) {
var element = myNodeList[i];
myElements.push(element);
};
Después de eso, no dude en llamar .innerHTML o .style o algo sobre los elementos de su matriz.
Yo también aconsejo usar la manera simple (KISS! -)
- pero se puede encontrar algo de optimización, es decir, no probar la longitud de una matriz más de una vez:
var elements = document.getElementsByTagName(''div'');
for (var i=0, im=elements.length; im>i; i++) {
doSomething(elements[i]);
}