2012-06-13 15 views
5

Więc czytałem o tasowaniu tablicy. I wtedy natknąłem this script:Pętla for bez {}

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

Kiedy patrzę bliżej, for nawet nie mają żadnego {} w ogóle! Ale działa, jak magia. Jestem bardzo ciekawy, jak to działa. (a grono przecinkami zbyt.)

+0

Jeśli istnieje tylko jedna pętla, skrypt będzie działał, ale jeśli masz więcej niż jeden zaraz po drugim, musisz oddzielić instrukcje. – Rayshawn

Odpowiedz

10

co za tym idzie for() może być dowolny rachunek; może to być coś z nawiasami klamrowymi lub może być pojedynczym wyrażeniem lub może być pustym wyrażeniem. for (...); jest odpowiednikiem for (...) {}. Oczywiście, powinno to być używane tylko w połączeniu z pętlą for, która zakończy się naturalnie, lub będziesz miał nieskończoną pętlę na twoich rękach.

Przecinki to efektywnie drugorzędne średniki; tworzą one dla większości oddzielne zdania, ale które będą działać w pętli for (i gdzie indziej, jest to bardzo niechlujna definicja).

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 

ten można umieścić w bardziej czytelnej postaci:

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

jako pętla while, które mogłyby być:

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()' jest bardziej zrozumiałym IMO. –

+0

Rzeczywiście, jest to bardziej zrozumiałe w ten sposób. –

1

Jeśli to wszystko w jednej linii, bez nawiasy są konieczne. Wiele razy w trzeciej sekcji w nawiasie widzisz tylko i++ lub coś w tym stylu. Naprawdę, możesz tam robić wiele różnych rzeczy. Jeśli jesteś w stanie spakować wszystko w tej trzeciej sekcji, nie potrzebujesz nawet ciała do pętli for.

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

Pierwszy odcinek

Zmienne są deklarowane i inicjalizowane. Te zmienne są zawarte w zasięgu pętli.

Druga sekcja

Jest to warunek sprawdzany przy każdym przejściu pętli.

Trzecia sekcja

kod, który biegnie po każdym przejściu przez pętlę. Może być tak proste, jak inkrementowanie zmiennej, i tak złożone, jak ... cóż, wszystko, co można zmieścić na linii, o ile składnia jest poprawna.

+0

Właściwie to nie ma linii. W ogóle nie ma ciała dla pętli. – TheHippo

1

Wygląda na to, że nie czytałem poprawnie pętli.

W tym przypadku oceny odbywają się w warunkach pętli for.

Więc pętli for ma trzy części

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

zdefiniować pewne wstępne rzeczy i używają o który został przekazany do funkcji, określające postępowanie w sprawie zakończenia, a następnie obliczyć coś każdej iteracji. Na końcu o ma nową wartość i zostaje zwrócona.

+0

Nie, nie jest. (w tym przypadku) Zobacz ');' na końcu 'for();'? –

+0

Przepraszam, błędnie przeczytałem nawias. zaktualizowałem moją odpowiedź. – sachleen

4

Każde obliczenie jest w tym samym oświadczeniu dla pojedynczego zdania, nie potrzebujemy {}, ale także w tym oświadczeniu; (na końcu używany jest terminator zdań) oznacza to, że następna instrukcja nie należy do instrukcji. Niezależnie od logiki jest to samo w przypadku stwierdzenia.

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

Cała praca jest faktycznie wykonywana w ramach instrukcji oświadczenia for. Nie ma wyraźnego ciała dla pętli, więc na końcu ; mówi się, że ciało jest pustym stwierdzeniem.

Operator (przecinek) ocenia wyrażenia od lewej do prawej i zwraca wartość z prawej strony.

Pętla jest w zasadzie równoważne:

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

Dlaczego 'i> 0;'? –

+0

Kiedy javascript ocenia stan pętli ('i'), sprawdza wartość true dla każdej wartości niezerowej, a wartość false, gdy wartość wynosi 0. Mówiąc" i> 0 "jest po prostu bardziej wyraźny sposób powiedzenia tego samego. Pętla odlicza od długości tablicy do 0. –

2

Po pierwsze, chciałbym zwrócić uwagę, że taka pętla jest uważana za zły styl, ponieważ jest bardzo nieczytelna i powoduje wiele zamieszania. Jest to typowy przykład niepowodzenia optymalizacji.

Patrząc na specs, po for(...) musi następować instrukcja . Może to być any statement, w tym bloki. Więc to wszystko jest ważne:

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

,

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

,

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

i oczywiście

for (...) 
    ; 

ponieważ ";" jest empty statement. Nie robi nic, ale wystarcza, aby uczynić for(...); syntaktycznie poprawną.

Teraz, dla przecinków. Zauważ, że zawartość parens musi być trzy expressions (każda z nich opcjonalna), oddzielone średnikami. Niemal "wszystko" kwalifikuje się jako wyrażenia, w tym comma-separated lists of expressions. Choć mało znane, działają one praktycznie wszędzie w JS, nie tylko w pętlach for. Są one po prostu oceniane jeden po drugim.

Tak, pętla może być zapisane jak tak

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

Również x = o[--i] powinien być zapisany jako i--; x = o[i].

+0

'musi następować po oświadczeniu ...' Nie do końca, w specyfikacji: 'b. Niech "stmt" będzie wynikiem oceny "Statement". do. Jeśli stmt.value nie jest pusta, ... 'Musi sprawdzić, czy coś jest, ponieważ" Statement "może być puste. –

+0

"Nie ma kontroli, czy coś jest" - cóż, mówi * Oświadczenie * kursywą, więc musi istnieć [instrukcja] (http://es5.github.com/#x12), której nie można "nic". Jego * wartość * może być pusta, weźmy na przykład instrukcję 'return;'. – user123444555621

+0

To jest mylące. Tak więc * nic * nie jest interpretowane jako * nic * lub * EmptyStatement *? –