2012-03-02 28 views
6

Tôi sẽ nhanh chóng và chuyển thẳng đến vụ án. Mã được nhận xét để bạn biết ý định của tôi. Về cơ bản, tôi đang xây dựng một trò chơi nhỏ dựa trên HTML5 và phản đối việc lưu nội dung trên máy chủ hoặc trong cookie, tôi sẽ chỉ cung cấp cho người chơi một mã cấp. Khi người chơi nhập mã (dưới dạng một băm đơn giản) vào trường nhập văn bản và nhấp vào nút để tải cấp đó, hàm "l" được gọi. Chức năng đó trước tiên truy xuất các mục nhập của người chơi, sau đó lặp qua danh sách các băm và so sánh chúng. Khi một trận đấu phù hợp, mức độ nhất định được cho là được tải, nhưng có lỗi. Tôi đã làm một chút gỡ lỗi, và tôi phát hiện ra rằng giá trị của iterator ("i"), đã thay đổi bên trong một setTimeout! Tôi muốn tạm dừng 1 giây, bởi vì tải mức độ ngay lập tức sẽ chỉ đơn giản là quá nhanh và sẽ trông xấu.setTimeout dường như đang thay đổi các biến của tôi! Tại sao?

levelCodes = //Just a set of "hashes" that the player can enter to load a certain level. For now, only "code" matters. 
[ 
    {"code": "#tc454", "l": 0}, 
    {"code": "#tc723", "l": 1}, 
] 

var l = function() //This function is called when a button is pressed on the page 
{ 
    var toLoad = document.getElementById("lc").value; //This can be "#tc723", for example 

    for (i = 0; i < levelCodes.length; i++) //levelCodes.length == 2, so this should run 2 times, and in the last time i should be 1 
     if (levelCodes[i].code == toLoad) //If I put "#tc723" this will be true when i == 1, and this happens 
     { 
      console.log(i); //This says 1 
      setTimeout(function(){console.log(i)}, 1000); //This one says 2! 
     } 
} 
+1

Nhận xét hay, có tất cả các phiếu bầu. – ninjagecko

+0

FYI, mã của bạn không vượt qua jslint vì một vài lý do và sẽ tạo ra lỗi trong một số trình duyệt –

+0

@MarkSchultheiss, vui lòng giải thích, tôi nghĩ rằng jsLint là một loại đánh giá, đúng không? Vậy thì, bạn có thể cho tôi biết tại sao tính toán này không? – corazza

Trả lời

3

Vòng lặp for tục increments i cho đến khi điều kiện lặp được đáp ứng, mặc dù các mã trong vòng lặp for không thực hiện, khi các mã trong setTimeout thực hiện nó cho thấy giá trị hiện của i - mà là 2.

4

ECMAscript sử dụng kỹ thuật lexical closures không có gì khác ngoài bộ nhớ trong cho tất cả các đối tượng bối cảnh mẹ/bản ghi môi trường từ vựng (ES3/ES5).

Nói cách ngắn gọn, chức năng ẩn danh của bạn được sử dụng bởi setTimeout đóng trên đó i biến, vì vậy trong khi thời gian chờ đó là "chờ", vòng lặp của bạn tiếp tục. setTimeout operatores asynronously tất nhiên và do đó chỉ làm phương tiện, vào thời điểm đó vòng lặp đã hoàn thành giá trị nếu i là tất nhiên 2.

Bây giờ nhớ về những thứ đóng cửa, chức năng ẩn danh của chúng tôi trong setTimeout vẫn giữ một tham chiếu đến i khi nó cuối cùng đã cháy (sau 1000ms). Vì vậy, nó chính xác cho bạn thấy giá trị của 2.

Nếu bạn muốn hiển thị các số cho mỗi lần lặp sau 1000 mili giây, bạn cần phải gọi một ngữ cảnh khác. Điều này có thể trông giống như

setTimeout((function(local) { 
    return function() { 
     console.log(local); 
    }; 
}(i)), 1000); 
+0

+1 ví dụ với địa chỉ rõ ràng –

5

Những người khác đã viết lý do cho hành vi bạn đang nhận được. Bây giờ là giải pháp: thay đổi dòng setTimeout tới:

(function(i) { 
    setTimeout(function(){console.log(i)}, 1000); 
})(i); 

này hoạt động bởi vì nó còn thể hiện giá trị hiện tại của biến i vào nhưng khác đóng cửa, và các biến trong việc đóng cửa mà không thay đổi.

+0

+1, nhưng để làm cho nó hoàn toàn rõ ràng: (hàm (iwas) { setTimeout (function() {console.log (iwas)}, 1000);}) (i); - chuyển 'i' trong số –

1

Bằng cách gọi lại thời gian setTimeout được thực hiện biến i sẽ có một giá trị của 2, bởi vì bạn không bỏ vòng lặp và i giữ đếm cho đến khi nó bằng levelCodes.legnth (đó là 2). Về cơ bản, bạn cần thêm trả lại hoặc ngắt sau khi gọi setTimeout. Ngoài ra, bạn không khai báo biến số i, do đó, nó sẽ bị ràng buộc vào không gian tên chung, điều này rất tệ và có thể dẫn đến các lỗi rất mơ hồ. Ví dụ, giá trị của i có thể được thay đổi trong các chức năng khác để gọi lại setTimeout sẽ thấy một giá trị khác. Bạn cần thêm var i; khi bắt đầu chức năng l.

+0

Tôi thấy rằng biến toàn cầu ngụ ý i cũng –

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