2010-10-18 32 views
5

Câu hỏi của tôi thực sự là một sự hiểu biết - Tôi có một giải pháp làm việc, tôi chỉ không hiểu cách hoạt động của nó.Câu hỏi hiểu biết về phạm vi toàn cầu biến thiên

Được rồi, vì vậy - những gì tôi đang cố gắng làm là thêm một setTimeout trong một vòng lặp và chuyển giá trị thay đổi thông qua nó. Ví dụ:

for (i=0;i<11;i++) 
{ 
    setTimeout("alert(i)",1000); 
} 

Nếu tôi hiểu đúng, làm việc doesnt này vì Javascript không (như PHP) vượt qua giá trị của i với chức năng, nhưng qua một tham chiếu của tôi - do đó không phải là tĩnh, nhưng vẫn tiếp tục để thay đổi với bộ đếm.

Tôi tìm thấy một giải pháp, mà đi như thế này:

for (i=0;i<11;i++) 
{ 
    setTimeout(function(x){return function(){alert(x)};}(i),1000); 
} 

tôi không thực sự hiểu những gì này thực hiện. Có vẻ như nó chuyển một chức năng "cảnh báo" trở lại chức năng gọi điện, nhưng tôi không thể hiểu được điều đó.

Tôi có thể làm việc với giải pháp này và cũng thích ứng với các ngữ cảnh khác, nhưng tôi thực sự muốn hiểu tất cả mã của tôi, không chỉ sử dụng những thứ tôi tìm thấy ở đâu đó và vui vẻ. Và ngoài ra, tôi đang tìm kiếm một phiên bản mỏng hơn để đạt được cùng một mục tiêu.

Cảm ơn, Marco

+3

+1 cho "Tôi thực sự muốn hiểu tất cả mã của tôi, không chỉ sử dụng nội dung tôi tìm thấy ở đâu đó và vui vẻ khi hoạt động" –

Trả lời

2

Lý do bạn đang gọi điện thoại một hàm trả về một chức năng là bạn cần phải có một cách nào đó cho chức năng được thông qua để setTimeout() có một tham chiếu đến giá trị hiện của i.

Bởi vì mã đợi để chạy cho 1000ms, các for vòng lặp sẽ được hoàn thành trước khi nó chạy, và giá trị nếu i sẽ 11.

Nhưng vì một hàm có phạm vi biến riêng của mình, bạn có thể vượt qua giá trị của i vào hàm đang được gọi ngay lập tức, do đó nó được tham chiếu bởi biến cục bộ x, mà hàm được trả về có thể tham chiếu khi setTimeout() cuối cùng gọi nó.

for (i=0; i<11; i++) { 
    setTimeout(function(x){ 
       // CONTINUE HERE: 
       // x is a local variable to the function being executed 
       // which references the current value of i 

       // A function is being returned to the setTimeout that 
       // references the local x variable 
       return function(){ alert(x); }; 

       }(i) // START HERE: 
        // The "outer" function is executed immediately, passing the 
        // current value of "i" as the argument. 
    ,1000); 
} 

Vì vậy, bạn đang dừng lại với một tương đương đó sẽ là một cái gì đó như thế này:

setTimeout(function(){ alert(x); }, 1000); //...where x === 0 
setTimeout(function(){ alert(x); }, 1000); //...where x === 1 
setTimeout(function(){ alert(x); }, 1000); //...where x === 2 
setTimeout(function(){ alert(x); }, 1000); //...where x === 3 
// etc. 
+0

Patrick, cảm ơn bạn rất nhiều. Đây có lẽ là liên kết còn thiếu. –

+0

@Marco P. - Bạn được chào đón. : o) – user113716

4

Điều này không:

function(x){return function(){alert(x)};}(i) 

là phải mất một chức năng:

function(x){ ...code... } 

Và thực hiện nó ngay, đi qua i (từ for loop) trong tham số duy nhất (đó là những gì (i) ở cuối là cho). Đây lợi nhuận khác chức năng:

function(){ alert(x); } 

Đó chính là kết quả đó được truyền cho setTimeout() như chức năng cuộc gọi khi bộ đếm thời gian, và nó không phải tham chiếu đến biến i trong vòng lặp của bạn đó đang thay đổi, đó là bằng cách sử dụng bản sao đã được chuyển vào khi nó tạo ra chức năng mới.

+0

Cảm ơn bạn đã dành thời gian giải thích điều này cho tôi - "+1". Nó thực sự đúng, tất cả các trang của tôi (airports.palzkill.de) - ngoại trừ các công cụ của Google - là selfmade. –

0

Patrick và Nick đã giúp tôi một việc lớn trong việc tìm hiểu toàn bộ sự việc, vì vậy tôi muốn tóm tắt nó cho tất cả mọi người có cùng một vấn đề với tôi:

setTimeout (cũng như một số chức năng trì hoãn thời gian khác như eventlisteners) có vẻ như lưu trữ gọi lại dưới dạng chuỗi và sau đó sử dụng một số loại nội bộ trên chuỗi này, do đó diễn giải nó như mã.

Điều đó gây ra vấn đề với vòng lặp và chức năng bị trì hoãn theo thời gian, vì tham chiếu của chúng tới biến đề cập đến kết quả cuối cùng của vòng lặp đó hoặc có thể là biến không phải là toàn cầu.

Như tôi đã hiểu, giải pháp với chức năng-trong-một chức năng giải quyết vấn đề này bằng cách đưa chuỗi trở lại dưới dạng kết quả hàm, sau đó chứa giá trị, chứ không phải tham chiếu đến biến (alert("1") không alert(i)) .

Liên quan đến việc làm cho mã ngắn hơn, tâm trí đơn giản của tôi đã đến một giải pháp đơn giản. Khi callback được kỳ vọng sẽ là một chuỗi, tại sao không viết các biến giá trị vào chuỗi này, và sau đó trả lại rằng:

for (i=0;i<11;i++) 
{ 
    setTimeout("alert("+i+")",1000); 
} 

Khách quan mà điều này có lẽ không phải là giải pháp tốt nhất, nhưng vì nó đòi hỏi số tiền nhỏ nhất của mã và số lượng tài nguyên não nhỏ nhất để hiểu cách thức và lý do nó hoạt động trái ngược với các giải pháp khác, tôi có thể làm việc với nó ngay bây giờ.

Một lần nữa xin cảm ơn Patrick, Nick và anh chàng không rõ đã rút lại câu trả lời của mình vì đã dành thời gian giúp tôi với điều này!

+0

Marco - Bạn đã hiểu đúng một phần. Một 'setTimeout' có thể chấp nhận một String cho đối số của nó, sau đó nó sẽ cố gắng' eval'. Nếu một phương thức (như cảnh báo) tồn tại trong không gian tên chung, nó sẽ kích hoạt. Nhưng 'setTimeout' cũng có thể chấp nhận một đối tượng hàm làm đối số. Điều này được thực hiện bằng cách chuyển một hàm ẩn danh (mà mã trong ví dụ của bạn đã trở về), hoặc bằng cách chuyển một tham chiếu biến tới một hàm. Nếu một hàm nhận được, nó sẽ được gọi trong không gian tên chung bất kể thực tế là nó có thể có nguồn gốc trong phạm vi riêng. Trong js, bạn có thể truyền các hàm xung quanh như thế này. – user113716

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