2012-06-13 13 views
5

Así que estaba leyendo acerca de cómo mezclar una matriz. Y entonces me encontré con this script:A for loop sin {}

shuffle = function(o){ //v1.0 
    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; 
}; 

Cuando miro de cerca, la for ni siquiera tiene ningún {} en absoluto! Pero está funcionando, como la magia. Tengo mucha curiosidad por saber cómo funciona. (y el manojo de comas demasiado.)

+0

Si solo hay un bucle for, el script funcionará, pero si tiene más de uno justo después del otro, debe separar los enunciados. – Rayshawn

Respuesta

10

lo que sigue la for() puede ser cualquier sentencia; eso puede ser algo con llaves, o puede ser una expresión única, o puede ser una expresión vacía. for (...); es equivalente a for (...) {}. Naturalmente, esto solo debe usarse junto con un bucle for que terminará naturalmente, o tendrá un bucle infinito en sus manos.

Las comas son efectivamente punto y coma de segundo grado; hacen declaraciones en su mayoría separadas, pero que funcionarán en un bucle for (y en otro lugar, esta es una definición muy descuidada de ellas).

for (
    // initialisation: declare three variables 
    var j, x, i = o.length; 
    // The loop check: when it gets to ``!i``, it will exit the loop 
    i; 
    // the increment clause, made of several "sub-statements" 
    j = parseInt(Math.random() * i), 
    x = o[--i], 
    o[i] = o[j], 
    o[j] = x 
) 
    ; // The body of the loop is an empty statement 

Esto podría ser puesto en una forma más fácil de leer como:

for (
    // initialisation: declare three variables 
    var j, x, i = o.length; 
    // The loop check: when it gets to ``!i``, it will exit the loop 
    i; 
    // note the increment clause is empty 
) { 
    j = parseInt(Math.random() * i); 
    x = o[--i]; 
    o[i] = o[j]; 
    o[j] = x; 
} 

Como un bucle while, que podrían ser:

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

'while()' es más comprensible IMO. –

+0

De hecho, es más entendible de esa manera. –

1

Si todo está en una línea, no hay soportes son necesarios. Muchas veces en esa tercera sección dentro del paréntesis, solo ves i++, o algo así. Realmente, puedes hacer muchas cosas diferentes allí. Si puede empaquetar todo en esa tercera sección, ni siquiera necesita un cuerpo para el bucle for.

for (first section; second section; third section); 

Primera sección

Las variables se declaran e inicializan. Estas variables están contenidas por el alcance del ciclo.

Segunda sección

Esta es la condición comprobado con cada pasada del bucle.

Tercera sección

código que se ejecuta después de cada pasada a través del lazo. Puede ser tan simple como incrementar una variable, y tan complejo como ... bueno, cualquier cosa que pueda caber en la línea, siempre que la sintaxis sea correcta.

+0

En realidad, no hay línea. No hay ningún cuerpo para el ciclo en absoluto. – TheHippo

1

Parece que no leí el ciclo correctamente.

En este caso, las evaluaciones se realizan dentro de las condiciones del bucle for.

Así que un bucle for tiene tres partes

for (initial variables; end cases; what to do every iteration) 

definiría usted un poco de materia inicial y utiliza o que fue aprobada en la función, defina un caso extremo, y luego calcular algo cada iteración. Al final, o tiene un nuevo valor y se devuelve.

+0

No, no lo es. (en este caso) Ver el ');' al final de 'for();'? –

+0

Perdón, leí mal el paréntesis. actualicé mi respuesta. – sachleen

4

Cada computación tiene el mismo enunciado para una sola declaración que no necesitamos {} pero también en esta declaración; (el finalizador de frase se usa al final) significa que la siguiente declaración no pertenece a la instrucción for. Cualquiera que sea la lógica, está en lo mismo para la declaración.

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


    for(var j, x, i = o.length;// Initialization 
    i;// Work until i is zero 
j = parseInt(Math.random() * i), 
    x = o[--i], o[i] = o[j], o[j] = x);//Here he is computing his logic 
0

Todo el trabajo en realidad se está haciendo dentro de los parens de la declaración for. No hay un cuerpo explícito para el ciclo, por lo que el ; al final solo dice que el cuerpo es una declaración vacía.

El operador , (coma) evalúa las expresiones de izquierda a derecha y devuelve el valor del más correcto.

El bucle es básicamente equivalente a:

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

¿Por qué 'i> 0;'? –

+0

Cuando javascript evalúa la condición de bucle ('i') se evalúa como verdadero para cualquier valor distinto de cero, y falso cuando el valor es 0. Decir' i> 0' es solo una forma más explícita de decir lo mismo. El ciclo cuenta regresivamente desde la longitud de la matriz a 0. –

2

En primer lugar, me gustaría señalar que dicho bucle se considera de mal estilo, ya que es muy ilegible y causa mucha confusión. Este es un ejemplo típico de optimización que salió mal.

Mirando el specs, usted encontrará que for(...) debe ir seguido de una declaración. Puede ser any statement, incluidos los bloques. Así que todos estos son válidas:

for (...) 
    foo; // expression statement 

,

for(...) 
    { 
     // block statement 
    } 

,

for(...) 
    if(...) // If statement 
     foo; 

, y por supuesto

for (...) 
    ; 

ya que ";" es el empty statement. No hace nada, pero es suficiente para hacer que for(...); sea sintácticamente válido.

Ahora, para las comas. Tenga en cuenta que los contenidos de los parens deben ser tres expressions, (cada uno de ellos opcional), separados por punto y coma. Casi todo "todo" califica como expresiones, incluido comma-separated lists of expressions. Aunque poco conocidos, funcionan básicamente en todos lados en JS, no solo en los bucles for. Simplemente son evaluados uno después del otro.

Así, el bucle se puede reescribir como tal

shuffle = function(o) { 
    var j, x, i = o.length; 
    while (i) { // for-loops are just while-loops in disguise 
     j = parseInt(Math.random() * i), // even better: replace , by ; 
     x = o[--i], 
     o[i] = o[j], 
     o[j] = x; 
    } 
    return o; 
}; 

Además, x = o[--i] debe escribirse como i--; x = o[i].

+0

'debe ir seguido de una declaración ...' No realmente, en las especificaciones: 'b. Deje que "stmt" sea el resultado de evaluar "Statement". do. Si stmt.value no está vacío, ... 'Tiene que verificar si hay algo, porque" Statement "puede estar vacío. –

+0

"No tiene control si hay algo" - bueno, dice * Statement * en cursiva, por lo que tiene que haber una [instrucción] (http://es5.github.com/#x12), que no puede ser "nada". Su * valor * puede estar vacío, tome por ejemplo la instrucción 'return;'. – user123444555621

+0

Esto es confuso. Entonces * nada * se interpreta como * nada * o un * EmptyStatement *? –