2012-06-13 19 views
5

Quindi stavo leggendo di mischiare un array. E poi mi sono imbattuto in this script:Un ciclo for senza {}

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; 
}; 

Quando guardo da vicino, il for non ha nemmeno alcun {} a tutti! Ma sta funzionando, come per magia. Sono molto curioso di sapere come funziona. (e il mazzo di virgole troppo.)

+0

Se c'è solo un ciclo for, lo script funzionerà, ma se ne hai più di uno dopo l'altro, devi separare le istruzioni. – Rayshawn

risposta

10

sulle seguenti for() può essere alcuna dichiarazione; che può essere qualcosa con parentesi graffe, o può essere una singola espressione, o può essere un'espressione vuota. for (...); equivale a for (...) {}. Naturalmente, questo dovrebbe essere usato solo in combinazione con un ciclo for che termina naturalmente, o avrai un loop infinito sulle tue mani.

Le virgole sono effettivamente punti e virgola di seconda scelta; creano dichiarazioni per lo più separate, ma che funzioneranno in un ciclo for (e altrove, questa è una definizione molto approssimativa).

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 

Questo potrebbe essere messo in una forma più leggibile come:

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; 
} 

Come un ciclo while, che potrebbe essere:

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()' è più comprensibile IMO. –

+0

In effetti, è più comprensibile in questo modo. –

1

Se è tutto su una riga, non sono necessarie le staffe. Un sacco di volte in quella terza sezione all'interno della parentesi, si vede semplicemente i++, o qualcosa del genere. Davvero, puoi fare molte cose diverse lì. Se riesci a mettere tutto in quella terza sezione, non hai nemmeno bisogno di un corpo per il ciclo for.

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

Prima sezione

variabili sono dichiarate e inizializzate. Queste variabili sono contenute nell'ambito del ciclo.

seconda sezione

Questa è la condizione verificata ad ogni passaggio del ciclo.

terza sezione

codice che viene eseguito dopo ogni passaggio attraverso il ciclo. Può essere semplice come incrementare una variabile e complessa come ... beh, qualsiasi cosa tu possa adattare alla linea, a patto che la sintassi sia corretta.

+0

In realtà nessuna linea. Non esiste alcun corpo per il ciclo. – TheHippo

1

Sembra che non abbia letto correttamente il ciclo.

In questo caso, le valutazioni si verificano all'interno delle condizioni del ciclo for.

Quindi un ciclo for ha tre parti

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

È definire alcuni roba iniziale e utilizzare o che è stato passato alla funzione, definire un caso estremo e poi calcoliamo qualcosa ogni iterazione. Alla fine, o ha un nuovo valore e viene restituito.

+0

No, non lo è. (in questo caso) Vedere ');' alla fine di 'for();'? –

+0

Mi dispiace di aver letto male la parentesi. aggiornato la mia risposta. – sachleen

4

Ogni calcolo è nella stessa istruzione per singola istruzione non è necessario {} ma anche in questa dichiarazione; (terminatore di frase è usato alla fine) significa che la prossima istruzione non appartiene a per la dichiarazione. Qualunque sia la logica è nella stessa dichiarazione.

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

Tutto il lavoro è stato fatto in realtà all'interno delle parentesi della dichiarazione for. Non esiste un corpo esplicito per il ciclo, quindi lo ; alla fine dice solo che il corpo è un'istruzione vuota.

L'operatore , (virgola) valuta le espressioni da sinistra a destra e restituisce il valore più a destra.

Il ciclo è sostanzialmente 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

Perché 'i> 0;'? –

+0

Quando javascript valuta la condizione del ciclo ('i'), viene valutata su true per qualsiasi valore diverso da zero e false quando il valore è 0. Dire" i> 0' è solo un modo più esplicito di dire la stessa cosa. Il ciclo esegue il conto alla rovescia dalla lunghezza dell'array a 0. –

2

In primo luogo, vorrei sottolineare che tale loop è considerato di cattivo gusto, poiché è molto illeggibile e causa molta confusione. Questo è un tipico esempio di ottimizzazione andato male.

Guardando il specs, vi accorgerete che for(...) deve essere seguita da una dichiarazione . Può essere any statement, compresi i blocchi. Quindi, tutti questi sono validi:

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

,

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

,

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

, e, naturalmente,

for (...) 
    ; 

dal ";" è il empty statement. Non fa nulla, ma è sufficiente a rendere for(...); sintatticamente valido.

Ora, per le virgole. Si noti che il contenuto del paren deve essere tre expressions, (ciascuno facoltativo), separati da punto e virgola. Praticamente "tutto" si qualifica come espressione, incluso comma-separated lists of expressions. Sebbene poco conosciuti, questi funzionano praticamente ovunque in JS, non solo nei loop for. Vengono semplicemente valutati uno dopo l'altro.

Così, il ciclo può essere riscritta in questo modo

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; 
}; 

Inoltre, x = o[--i] dovrebbe essere scritto come i--; x = o[i].

+0

'deve essere seguito da una dichiarazione ...' Non proprio, nelle specifiche: 'b. Lascia che "stmt" sia il risultato della valutazione di "Statement". c. Se stmt.value non è vuoto, ... 'È necessario verificare se c'è qualcosa, perché" Statement "può essere vuoto. –

+0

"Non ha alcun controllo se c'è qualcosa di" - beh, si dice * Dichiarazione * in corsivo, quindi ci deve essere un [dichiarazione] (http://es5.github.com/#x12), che può non essere "Niente". Il suo * valore * può essere vuoto, prendi ad esempio l'istruzione 'return;'. – user123444555621

+0

Questo è confuso. Quindi * niente * è interpretato come * nothing * o * EmptyStatement *? –