2008-10-11 10 views
28

he tropezado con varios métodos de bucle en JavaScript, lo que más me gusta es:¿Cuál es la mejor manera de hacer bucles en JavaScript

for(var i = 0; i < a.length; i++){ 
    var element = a[i]; 
} 

Pero como prueba aquí (http://www.robertnyman.com/2008/04/11/javascript-loop-performance/), que probablemente debería ser escrito de modo que la duración solo se calcule una vez.

En jQuery hay una cada vez que puede ejecutar una función. Me gusta un poco mejor, porque no tengo que escribir la matriz dos veces, como en la solución anterior.

Si las macros soportadas por JavaScript sería una tarea fácil, pero lamentablemente no es así.

¿Qué usan?

+0

Aparentemente, lo que quiere decir con "mejor" es "más limpio", ¿no? Algunos podrían decir que la "mejor" manera es hacerlo de la manera más rápida posible, en cuyo caso la respuesta probablemente sea diferente ... –

+0

Sí, bueno. Elegí la palabra mejor, porque quería una solución de bucle que pueda usar siempre sin pensar realmente en ello.Por lo tanto, no debe ser terriblemente lento cuando se ejecuta en 100k elementos, no debe ser terriblemente largo para escribir, etc. –

Respuesta

36

He comenzado a usar iteradores cuando sea relevante. El rendimiento es razonable, sin embargo es más importante que le permite encapsular la lógica de bucle:

function createIterator(x) { 
    var i = 0; 

    return function(){ 
     return x[i++]; 
    }; 
} 

Luego de usar:

var iterator=createIterator(['a','b','c','d','e','f','g']); 

iterator(); 

devuelve "A";

iterator(); 

returns "b";

y así sucesivamente.

para recorrer toda la lista y mostrar cada elemento:

 
var current; 

while(current=iterator()) 
{ 
    console.log(current); 
} 

Tenga en cuenta que la anterior es sólo aceptable para repite una lista que contiene los valores "no Falsy". Si esta matriz contiene cualquiera de:

  • falsa
  • ""
  • nula
  • NaN

el bucle anterior se detendría en ese artículo, no siempre lo que se querer/esperar

Para evitar este uso:

var current; 

while((current=iterator())!==undefined) 
{ 
    console.log(current); 
} 
+0

Sí, también he estado pensando en usar iteradores. Encapsulan mucho mejor el concepto de atravesar algo que los simples bucles. Pero, ¿cómo imprimirías en tu ejemplo todos los elementos en el iterador? –

+0

Hermosa dulzura de cierre. Ahh, los amo. –

+0

¿Cómo sabes cuando has llegado al final si tu iterador no tiene una función HasNext? Si sigue llamando a "iterador" según su ejemplo, eventualmente obtendrá el índice de matriz fuera de límites. – Kibbee

2

Puede utilizar siempre un ciclo while y calcular el límite de la matriz de antemano.

Var max = a.length-1; 
var i = 0; 

while(i <= max) 
{ 
var element = a[i]; 
i++; 
} 
+0

Lamento ser franco, pero no veo cómo esto es una mejora. Aún se especifica la matriz dos veces, y en su solución el entorno está contaminado con dos variables que scrope no debe trascender la construcción del ciclo while. –

+0

El medio ambiente va a estar "contaminado" de todos modos, dado que en Javascript el alcance de una variable es la función adjunta, no el bloque en el que se declara. –

+0

Probándolo contra el enlace proporcionado en la pregunta, es al menos tan rápido, si no más rápido, que cualquiera de las implementaciones de bucle for. – Kibbee

9

pequeña mejora al original, sólo para calcular el tamaño de la matriz una vez:

for(var i = 0, len = a.length; i < len; i++){ var element = a[i]; } 

Además, veo un montón de bucles for..in. A pesar de tener en cuenta que técnicamente no es kosher, y causará problemas con el prototipo específicamente:

for (i in a) { var element = a[i]; } 
+1

for..in los bucles se utilizan para iterar sobre las propiedades del objeto, mientras que parecen funcionar para matrices, también iterarán sobre la propiedad 'longitud' o cualquier otro dinámicamente propiedad agregada Es por eso que no funciona bien con Prototype. –

+1

el segundo ejemplo 'i' probablemente está creando un – ajax333221

6

tienda sólo la longitud de una variable en primer lugar.

var len = a.length; 
    for (var i = 0; i < len; i++) { 
    var element = a[i]; 
    } 
1

Si tiene muchos elementos en la matriz y la velocidad es un problema, entonces desea utilizar un ciclo while que itere de mayor a menor.

var i = a.length; 
    while(--i >= 0) { 
    var element = a[i]; 
    // do stuff with element 
    } 
+0

global no es necesario> = 0, simplemente cambie --i a i-- –

1

yo no lo uso yo, pero uno de mis colegas utiliza este estilo:

var myArray = [1,2,3,4]; 
for (var i = 0, item; item = myArray[i]; ++i) { 
    alert(item); 
} 

como respuesta de Ash, esto llegará a problemas si tiene valores "Falsey" en su formación. Para evitar ese problema cámbielo a (item = myArray[i]) != undefined

6

Sé que llego tarde a la fiesta, pero utilizo los bucles inversos para los bucles que no dependen de la orden.

Muy similar a @Mr. La rata almizclera de - pero la simplificación de la prueba:

var i = a.length, element = null; 
while (i--) { 
    element = a[i]; 
} 
+0

y estoy * muy * tarde a la fiesta, pero esta es la respuesta correcta y debe ser aceptado como tal. Para los no iniciados, la cláusula i-- guarda una comparación (porque 0 = falso en las pruebas JS). Advertencia 1: orden inverso Advertencia 2: la legibilidad no es genial. Advertencia 3: un bucle en caché es casi tan bueno – annakata

-2

Por lo tanto, lo primero que identificar el bucle Javascript perfecta, creo que debería tener este aspecto:

ary.each (function() {$ argumentos [0]) .remove();})

Esto puede requerir la biblioteca prototype.js.

A continuación, obtienes disgusto con la parte de argumentos [0] y haces que el código se genere automáticamente desde tu estructura de servidor. Esto funciona solo si la escalera es Seaside.

Ahora, has lo anterior generado por:

do ary: [: cada uno | cada elemento eliminar].

Esto viene completo con la sintaxis completa y se traduce exactamente al javascript anterior. Y hará girar la cabeza a la gente que no haya utilizado antes la integración del prototipo de Seaside, mientras leen tu código. Seguro que te hace sentir genial también. Por no mencionar la ganancia en geekiness que puedes obtener aquí. ¡A las chicas les encanta!

0

No veo cuál es el problema con el uso de un estándar para el bucle (;;). Una pequeña prueba

var x; 
var a = []; 
// filling array 
var t0 = new Date().getTime(); 
for(var i = 0; i < 100000; i++) { 
    a[i] = Math.floor(Math.random()*100000); 
} 

// normal loop 
var t1 = new Date().getTime(); 
for(var i = 0; i < 100000; i++) { 
    x = a[i]; 
} 

// using length 
var t2 = new Date().getTime(); 
for(var i = 0; i < a.length; i++) { 
    x = a[i]; 
} 

// storing length (pollution - we now have a global l as well as an i) 
var t3 = new Date().getTime(); 
for(var i = 0, l = a.length; i < l; i++) { 
    x = a[i]; 
} 

// for in 
var t4 = new Date().getTime(); 
for(var i in a) { 
    x = a[i]; 
} 

// checked for in 
var t5 = new Date().getTime(); 
for(var i in a) { 
    if (a.hasOwnProperty(i)) { 
     x = a[i]; 
    } 
} 

var t6 = new Date().getTime(); 
var msg = 'filling array: '+(t1-t0)+'ms\n'+ 
      'normal loop: '+(t2-t1)+'ms\n'+ 
      'using length: '+(t3-t2)+'ms\n'+ 
      'storing length: '+(t4-t3)+'ms\n'+ 
      'for in: '+(t5-t4)+'ms\n'+ 
      'checked for in: '+(t6-t5)+'ms'; 
console.log(msg); 

resultados en:

filling array: 227ms 
normal loop: 21ms 
using length: 26ms 
storing length: 24ms 
for in: 154ms 
checked for in: 176ms 

Así: - en echar el más largo, el uso de la propiedad de longitud (que es una propiedad y no tiene que ser calculado) es casi tan rápido como almacenarlo primero - que es solo un bigote más lento que usar un número entero.
AND a for() es la forma habitual de recorrer una matriz, que todos esperan y entienden.

Todos ellos agregan una variable al ámbito en el que se ejecutan - i - que es un nombre común para este uso, por lo que no se debe usar para otras cosas. El almacenamiento de la longitud primero agrega otra var - l - al alcance, que es innecesario

Cuestiones relacionadas