2009-03-23 15 views
14

estaba desde hace bastante tiempo la impresión de que un bucle for podría existir exclusivamente en el siguiente formato:En cuanto JavaScript para voodoo() bucle

for (INITIALIZER; STOP CONDITION; INC(DEC)REMENTER) 
{ 
    CODE 
} 

Ésta es, sin embargo, la mayoría definitivamente no el caso; echar un vistazo a esta aplicación de JavaScript de Fisher-Yates Shuffle:

shuffle = function(o) 
{ 
    for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); 
    return o; 
}; 

Este pequeño fragmento sopla mi mente por completo; ¿Cómo está pasando tanto dentro de una simple declaración de bucle? Quiero decir ... ¡ni siquiera abre un corsé! Toda la magia se está haciendo allí dentro de la declaración for. Sería absolutamente maravilloso si alguien pudiera dar una explicación relativamente completa de cómo en el mundo este vudú está haciendo lo que hace. Muy apreciado de antemano.

+0

Esto no es específico de javascript, cualquier (?) lenguaje basado en C para el bucle se puede usar según la respuesta de Yuliy. –

+0

La CONDICIÓN DE PARADA se debe definir realmente como la CONDICIÓN DE CONTINUACIÓN ya que el ciclo continuará mientras la condición sea verdadera. –

Respuesta

11

El formato generalizado de un bucle (no es un para-en bucle) es

for (EXPRESSION_1 ; EXPRESSION_2 ; EXPRESSION_3) STATEMENT 

La primera expresión_1 es generalmente utilizado para inicializar la variable de bucle, expresión_2 es ​​la condición de bucle, y expression_3 es generalmente operación de incremento o disminución, pero no hay reglas que digan que deben comportarse así. Es equivalente a la siguiente bucle while:

EXPRESSION_1; 
while (EXPRESSION_2) { 
    STATEMENT 
    EXPRESSION_3; 
} 

Las comas son sólo un operador que combina dos expresiones en una sola expresión, cuyo valor es la segunda sub-expresión. Se usan en el ciclo for porque cada parte (separada por punto y coma) debe ser una sola expresión, no múltiples instrucciones.No hay realmente ninguna razón (excepto tal vez para ahorrar algo de espacio en el archivo) para escribir un bucle así desde que esto es equivalente:

shuffle = function(o) { 
    var j, x; 
    for (var i = o.length; i > 0; i--) { 
     j = parseInt(Math.random() * i); 
     x = o[i - 1]; 
     o[i - 1] = o[j]; 
     o[j] = x; 
    } 
    return o; 
}; 
8

INICIALIZADOR puede declarar e inicializar múltiples variables. STOP CONDITION es una prueba única (aquí es simplemente "i"), y INCREMENTER es una expresión que se ejecutará cada vez después del cuerpo (el operador de coma le permite tener múltiples subexpresiones, que se ejecutan todas). El cuerpo del bucle for es solo la declaración vacía ";"

+0

INCREMENTER no es un conjunto de declaraciones. Ni siquiera es una declaración. Es una expresión. Éste consiste en varias otras expresiones separadas por el operador de coma, que evalúa sus operandos de izquierda a derecha y devuelve el valor del último operando. –

+0

Tienes razón. Actualizando mi respuesta para reflejar esto – Yuliy

0

La primera cláusula inicializa cualquier variable que desee utilizar. La segunda cláusula es de hecho la condición de parada. La tercera cláusula incluye cualquier lógica que se ejecutará al final de cada iteración. Las declaraciones múltiples se pueden separar por comas.

4

Sintaxis de bucle for es: se ejecuta

for (pre-block; condition; post-loop-block) 
    loop-block; 

En primer lugar, pre-bloque, se definen diversas variables.

En cada bucle:

  1. condición de comprobación
  2. ejecutar loop-bloque
  3. ejecutar post-loop-bloque
  4. repetición de 1.
14
shuffle = function(o){ 
    for (
      var j,    // declare j 
       x,    // declare x 
       i = o.length;  // declare i and set to o.length 
      i;     // loop while i evaluates true 
      j = parseInt(Math.random() * i), // j=random number up to i 
      x = o[--i],   // decrement i, and look up this index of o 
      o[i] = o[j],  // copy the jth value into the ith position 
      o[j] = x   // complete the swap by putting the old o[i] into jth position 
     ); 
    return o; 
    }; 

Esto es comenzando con i igual al número de posiciones, y cada vez intercambiando las cartas yj, donde j es un número aleatorio hasta i cada vez, según el algoritmo.

Podría escribirse más simple sin el confuso conjunto de comandos, verdadero.

Por cierto, este es no el único tipo de bucle en javascript. También hay:

for(var key in arr) { 
     value = arr[key]); 
} 

Pero tenga cuidado, ya que esto también bucle a través de las propiedades de un objeto, incluyendo si se pasa en un objeto Array.

1

Simplemente han movido el cuerpo del lazo a la sección de incremento.Se puede volver a escribir el bucle for como un bucle while para tener una idea de lo que está haciendo:

shuffle=function(o) { 
    var j; //Random position from 0 up to the current position - 1 
    var x; //temp holder for swapping positions 
    var i=o.length; //current position 
    while(i>0) { // Loop through the array 
     j = parseInt(Math.random()*i); //get a lower position 
     x = o[--i]; // decrement the position and store that position's value in the temp var 
     o[i]=o[j]; // copy position j to position i 
     o[j]=x; // copy the temp value that stored the old value at position i into position j 
    } 
    return o; 
} 

son los initialzier ampliado a cabo, el cheque en el tiempo es la condición de parada Los tres primeros de Var y la cuerpo del tiempo es lo que se hizo en la porción incremental del for.

Editar: Se ha corregido por el comentario de Gumbo

+0

Solo 'i' está asignado a' o.length'. – Gumbo

1

Esa declaración no se conforman con su formato inicial.

Resulta que podría añadir más de una frase de cada uso "" (coma)

Así:

for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); 

se podría analizar como esta:

for (var j,       //INITIALIZER(s) 
     x, 
     i = o.length; 

    i;        // STOP CONDITION (i) 

    j = parseInt(Math.random() * i), // INC(DEC)REMENTER 
    x = o[--i], 
    o[i] = o[j], 
    o[j] = x); // CODE (;) 

Como ya ves, encaja completamente en tu formato inicial.

7

El código que cita está ofuscado en mi opinión. Hay formas mucho más claras de escribir la misma funcionalidad.

Sin embargo, su comprensión es más o menos correcta. El siguiente es exactamente el mismo código, a excepción de espacios en blanco y comentarios.

for (
    // Initializer 
    var j, x, i = o.length; 
    // Continue condition 
    i; 
    // Operation to be carried out on each loop 
    j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x 
) 
// empty body, equivalent to { } 
; 

Es mucho más clara para escribir el equivalente:

var j,x,i = o.length; 
while(i) { 
    j = parseInt(Math.random() * i); 
    x = o[--i]; 
    o[i] = o[j]; 
    o[j] = x; 
} 

Hay otras optimizaciones que se podrían hacer para mejorar la legibilidad - incluyendo el uso de while(i > 0) en lugar de while(i), y dividir el --i en un i-- en una línea separada.

Realmente no hay ninguna razón para que() exista, a excepción de la legibilidad. Estos dos son equivalentes:

{ // this block is to scope int i 
    int i=0; 
    while(i<100) { 
     myfunc(i); 
     i++; 
    } 
} 

for(int i=0; i<100; i++) { 
    myfunc(i); 
} 

Usted debe usar lo que sea más legible durante un tiempo determinado. Yo diría que el autor de tu código ha hecho lo contrario. Para ser justos, puede haber hecho esto con el fin de lograr un archivo JS más pequeño para una carga más rápida (este es el tipo de transformación que podría hacer un compactador de código automatizado).

+0

¿Cambiaste a C a mitad de respuesta? – Zach

+0

Oops :) El principio es el mismo sin embargo. – slim

1

esto va todo el camino de regreso a la sintaxis de C - de la que javascript está robó una manojo. El truco principal es el operador de coma que parece no aparecer casi en ningún otro lugar excepto por los bucles