2012-06-13 65 views
5

Vì vậy, tôi đã đọc về xáo trộn một mảng. Và sau đó tôi đi qua this script:Vòng lặp for mà không có bất kỳ {}

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

Khi tôi nhìn kỹ, các for thậm chí không có bất kỳ {} ở tất cả! Nhưng nó hoạt động, giống như phép thuật. Tôi rất tò mò muốn biết nó hoạt động ra sao. (và bó dấu phẩy quá.)

+0

Nếu chỉ có một vòng lặp thì tập lệnh sẽ hoạt động, nhưng nếu bạn có nhiều quyền sau tập lệnh kia thì bạn phải tách riêng các câu lệnh. – Rayshawn

Trả lời

10

gì sau những for() thể được bất kỳ tuyên bố; có thể là thứ có dấu ngoặc nhọn, hoặc nó có thể là một biểu thức duy nhất, hoặc nó có thể là một biểu thức trống. for (...); tương đương với for (...) {}. Đương nhiên, điều này chỉ nên được sử dụng kết hợp với một vòng lặp mà sẽ chấm dứt tự nhiên, hoặc bạn sẽ có một vòng lặp vô hạn trên tay của bạn.

Dấu phẩy là dấu chấm phẩy cấp hai hiệu quả; chúng tạo ra cho các câu lệnh chủ yếu là riêng biệt, nhưng nó sẽ làm việc trong một vòng lặp for (và ở nơi khác; đây là một định nghĩa rất cẩu thả của chúng).

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 

này có thể được đặt trong một hình thức dễ đọc hơn như:

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

Như một vòng lặp while, đó có thể là:

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()' là IMO dễ hiểu hơn. –

+0

Thật vậy, nó là dễ hiểu hơn theo cách đó. –

1

Nếu đó là tất cả trên cùng một dòng, không có dấu ngoặc là cần thiết. Rất nhiều lần trong phần thứ ba bên trong dấu ngoặc đơn, bạn chỉ cần xem i++ hoặc một cái gì đó tương tự. Thực sự, bạn có thể làm nhiều thứ khác nhau ở đó. Nếu bạn có thể đóng gói mọi thứ trong phần thứ ba đó, bạn thậm chí không cần một cơ thể cho vòng lặp for.

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

phần Đầu

biến được khai báo và khởi tạo. Các biến này được chứa bởi phạm vi của vòng lặp.

Thứ hai phần

Đây là điều kiện kiểm tra với mỗi đường đi qua của vòng lặp.

phần thứ ba

Mã chạy sau mỗi lần đi qua vòng lặp. Nó có thể đơn giản như tăng một biến, và phức tạp như ... tốt, bất cứ điều gì bạn có thể phù hợp trên dòng, miễn là cú pháp là chính xác.

+0

Thực ra nó không có dòng. Không có bất kỳ cơ thể cho vòng lặp ở tất cả. – TheHippo

1

Có vẻ như tôi không đọc chính xác vòng lặp.

Trong trường hợp này, các đánh giá đang diễn ra bên trong các điều kiện của vòng lặp for.

Vì vậy, một vòng lặp for có ba phần

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

Bạn xác định một số nội dung ban đầu và sử dụng o đã được thông qua vào chức năng, xác định một trường hợp kết thúc, và sau đó tính toán cái gì đó mỗi lần lặp. Cuối cùng, o có giá trị mới và được trả lại.

+0

Không, không. (trong trường hợp này) Xem ');' ở cuối 'for();'? –

+0

Xin lỗi tôi đã đọc sai dấu ngoặc đơn. đã cập nhật câu trả lời của tôi. – sachleen

4

Mọi máy tính đều có cùng một câu lệnh cho câu lệnh đơn mà chúng ta không cần {} nhưng cũng có trong tuyên bố này; (terminator câu được sử dụng cuối cùng) nó có nghĩa là tuyên bố tiếp theo không thuộc về tuyên bố. Dù logic là gì thì cũng giống như vậy đối với câu lệnh.

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

Tất cả công việc thực sự đang được thực hiện trong các mệnh đề của tuyên bố for. Không có cơ thể rõ ràng cho vòng lặp để ; ở cuối chỉ nói rằng cơ thể là một tuyên bố trống rỗng.

Toán tử , (dấu phẩy) đánh giá các biểu thức từ trái sang phải và trả về giá trị của bên phải.

Vòng lặp về cơ bản là tương đương với:

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

Tại sao 'i> 0;'? –

+0

Khi javascript đánh giá điều kiện vòng lặp ('i') nó đánh giá là đúng cho bất kỳ giá trị khác 0 và false khi giá trị bằng 0. Nói' i> 0' chỉ là một cách rõ ràng hơn để nói cùng một điều. Vòng lặp đếm ngược chiều dài của mảng đến 0. –

2

Trước tiên, tôi muốn lưu ý rằng vòng lặp như vậy được coi là kiểu xấu, vì nó rất dễ đọc và gây ra nhiều nhầm lẫn. Đây là một ví dụ điển hình về tối ưu hóa đã sai.

Nhìn vào specs, bạn sẽ thấy rằng for(...) phải được theo sau bởi một tuyên bố . Có thể là any statement, bao gồm các khối. Vì vậy, tất cả trong số này là hợp lệ:

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

,

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

,

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

, và tất nhiên

for (...) 
    ; 

vì ";" là empty statement. Nó không có gì, nhưng nó đủ để làm cho for(...); có hiệu lực về cú pháp.

Hiện tại, đối với dấu phẩy. Lưu ý rằng nội dung của các parens phải là ba expressions, (mỗi tùy chọn), được phân tách bằng dấu chấm phẩy. Khá nhiều "mọi thứ" đủ điều kiện làm biểu thức, bao gồm comma-separated lists of expressions. Mặc dù ít được biết đến, những công việc này về cơ bản ở khắp mọi nơi trong JS, không chỉ trong vòng for. Chúng đơn giản được đánh giá sau cái kia.

Vì vậy, vòng lặp của bạn có thể được viết lại như vậy

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

Ngoài ra, x = o[--i] nên được viết như i--; x = o[i].

+0

'phải được theo sau bởi một tuyên bố ...' Không thực sự, trong các thông số kỹ thuật: 'b. Hãy để "stmt" là kết quả của việc đánh giá "Statement". c. Nếu stmt.value không trống, ... 'Nó phải kiểm tra xem có gì không, bởi vì" Statement "có thể rỗng. –

+0

"Nó không có kiểm tra nếu có cái gì đó" - tốt, nó nói * Tuyên bố * in nghiêng, do đó, có phải là một [tuyên bố] (http://es5.github.com/#x12), mà không thể được "không có gì". Giá trị * của nó có thể rỗng, lấy ví dụ câu lệnh 'return;'. – user123444555621

+0

Điều này gây nhầm lẫn. Vì vậy, * không có gì * được hiểu là * không có gì * hoặc * EmptyStatement *? –

Các vấn đề liên quan