2011-08-26 45 views
5

Vì tôi là một newbie JavaScript, tôi bắt đầu học nó nhưng tôi đã bị mắc kẹt ngay từ đầu. Tôi đang theo dõi a Mozilla Tutorial và tôi gặp sự cố với phạm vi biến đổi trong JavaScript. Tôi có một số mã:Biến phạm vi vấn đề

var myvar = "my value"; 

var zmienna = "string"; 

(function() { 
    alert(myvar); 
    alert(zmienna); 
})(); 

(function() { 
    alert(myvar); // undefined 
    var myvar = "local value"; 
    alert(zmienna); 
})(); 

Trong hướng dẫn, tôi đã đọc các biến JavaScript không hiển thị từ các khối chức năng. Vâng, hai cảnh báo đầu tiên cho biết các giá trị chính xác. Đó là lạ sau đó, bởi vì cảnh báo thứ ba nói "không xác định", mặc dù thực tế là không có gì đã thay đổi từ khối chức năng trước đó. Thứ tư, một lần nữa, in giá trị đúng.

Ai đó có thể giải thích cho tôi, điều gì đang xảy ra ở đây? Tôi sẽ rất vui vì bài hướng dẫn không nói gì thêm về điều đó.

+0

_ "Tôi đã đọc rằng các biến JavaScript không nhìn thấy được từ khối chức năng. "_ Ở đâu trong hướng dẫn? Câu đó không có ý nghĩa. –

Trả lời

1

"Tôi đã đọc các biến JavaScript không hiển thị từ các khối chức năng".

Điều đó không đúng. Chúng có sẵn từ các hàm lồng nhau.

Chức năng lồng nhau tạo ra một chuỗi phạm vi . Một hàm được tạo bên trong một hàm khác có quyền truy cập vào các biến riêng của nó cũng như các biến của hàm mà nó được lồng vào nhau.

Nhưng chức năng A có thể không thấy các biến của hàm B nếu chức năng A đã không lồng bên chức năng B.

var myvar = "my value"; // <-- global variable, seen by all functions  
var zmienna = "string"; // <-- global variable, seen by all functions 

(function() { 
    alert(myvar); // <-- referencing the global variable 
    alert(zmienna); // <-- referencing the global variable 
})(); 
(function() { 
    // v--- Declaration of these "local" variables were hoisted to the top... 
    // var myvar; // <--- ...as though it was here. 
    // var new_var; // <--- ...as though it was here. 

    alert(myvar); // undefined (myvar is delcared, but not initialized) 
    alert(new_var); // undefined (new_var is delcared, but not initialized) 

    var myvar = "local value"; // <-- assign the value 

    alert(zmienna); // <-- referencing the global variable 
    alert(myvar); // <-- referencing the local variable 

    var new_var = "test"; // <-- another new local variable 

    // A nested function. It has access to the variables in its scope chain. 
    (function() { 
     alert(myvar); // <-- referencing the variable from its parent func 
     alert(new_var); // <-- referencing the variable from its parent func 
    })(); 
})(); 
/* 
Here's a new function. It was not nested inside the previous function, so it 
    has access to the global variables, and not the locals of the previous func 
*/ 
(function() { 
    alert(myvar); // <-- referencing the global variable 
    alert(new_var); // <-- ReferenceError 
})(); 
+0

Cảm ơn bạn rất nhiều vì câu trả lời của bạn. Bây giờ nó có vẻ hợp lý. Mặc dù, tôi phải thừa nhận, đối với tôi, Javascript là rất nhiều khó khăn hơn mà các ngôn ngữ khác mà tôi có một số kiến ​​thức về (chủ yếu là C + +, PHP và Erlang). Cảm ơn bạn một lần nữa. – Radi

+0

@Radi: Bạn được chào đón. Tôi có một số kiến ​​thức về Erlang, nhưng không có kiến ​​thức nào khác về Erlang.Hiện tượng này được gọi là * shadowing *, trong đó một hàm lồng nhau có thể khai báo một biến có cùng tên với một biến trong cha mẹ của nó, và vì vậy giá trị bạn nhận được phụ thuộc vào mức độ của chuỗi phạm vi bạn đang ở. tiếp cận với tổ tiên của họ. Nếu tôi nhớ lại, Erlang không cho phép đổ bóng vì gõ mạnh mẽ của nó, nhưng tôi có thể không nhớ chính xác. – user113716

+0

Vâng, thành thật mà nói, nó có thể biến đổi bóng trong Erlang, mặc dù trình biên dịch cảnh báo bạn về điều đó (kiểm tra này: https://gist.github.com/1173877) – Radi

9

Việc sử dụng var được treo.

Vì bạn có var myvar bên trong hàm, có một phạm vi cục bộ myvar. Vì bạn gán một giá trị cho nó sau khi bạn cảnh báo nó, nó là undefined khi bạn cảnh báo nó.

+0

Ok, cảm ơn. Nhưng tại sao hai cảnh báo đầu tiên lại hiển thị giá trị chính xác, mặc dù hướng dẫn đó khác nhau (như tôi đã hiểu, thay vì phải là "không xác định" vì thay vì nằm trong phạm vi khác nhau). Bạn có thể giải thích cho tôi điều đó không? – Radi

+1

Vì bạn có 'myvar' và' zmienna' được khai báo trong phạm vi toàn cầu. Vì vậy, chúng có thể truy cập từ mọi nơi trong tập lệnh của bạn, nếu không bị ẩn bởi các định nghĩa phạm vi cục bộ. – J0HN

+0

@Quentin: Có thể hiển thị OP mã tương đương thể hiện cho người mới bắt đầu những gì "hoisted" có nghĩa là và cách tuyên bố được hoisted nhưng nhiệm vụ là không. – user113716