2009-12-19 37 views
6

Tôi đã gặp sự cố rất lạ (đối với tôi) với từ khóa var. Tôi đã giảm nó thành một trường hợp thử nghiệm khá nhỏ và thấy nó được trưng bày trong Node.js (như vậy, V8 và Chrome), trình kiểm tra của Safari 4 (như vậy, Nitro) và FireBug (rõ ràng là SpiderMonkey). Ban đầu tôi đã chuẩn bị một báo cáo lỗi, nhưng vì nó được hiển thị rộng rãi, tôi sẽ giả định rằng tôi hoàn toàn hiểu sai cách JavaScript được cho là phạm vi và tra cứu các biến.Thao tác khó hiểu của từ khóa `var` của JavaScript

Trường hợp kiểm tra rất nhỏ và trên GitHub tại đây: http://gist.github.com/260067. Sự khác biệt duy nhất giữa ví dụ đầu tiên và thứ hai là việc bao gồm từ khóa var.

Ở đây, là tốt, là một trường hợp thử nghiệm tương tự mà thể hiện cùng một 'vấn đề' theo một cách khác: https://gist.github.com/698b977ee0de2f0ee54a

Edit: Để ngăn cản nhiều hơn bất kỳ câu trả lời cố gắng giải thích cách tầng phạm vi hoạt động, tôi m thân mật quen thuộc với điều đó. Vấn đề của tôi, là tôi không hiểu tại sao đoạn mã sau 'làm việc' (ở chỗ nó alert() s 'bên ngoài,' theo sau 'bên trong,' và sau đó một lần nữa 'bên ngoài'):

(function(){ 
    var foo = 'outer'; 
    alert("Outer `foo`: " + foo); 

    (function(){ 
    foo = 'inner'; 
    alert("Inner `foo`: " + foo); 

    var foo; 
    })(); 

    alert("Outer `foo`: " + foo); 
})(); 

Các var foo; xảy ra ở một vị trí hoàn toàn không liên quan đến việc phân bổ lại foo; vậy tại sao nó ảnh hưởng đến nhiệm vụ đó một cách rất quan trọng?

+0

Tại sao bạn sử dụng eval? Hoàn toàn không có lý do gì để sử dụng eval trong mã bạn đã đăng. – Marius

+0

Để chứng minh sự cố. Việc thực hiện thực tế là rất khác nhau; bạn có thể thấy nó trong tự nhiên ở đây: http://github.com/elliottcable/poopy.js/blob/new-acquire/lib/from.js#L193 – ELLIOTTCABLE

+0

Ví dụ cuối cùng của bạn hoạt động vì 1) foo = 'inner'; gán giá trị cho phạm vi foo chính mà hàm này có quyền truy cập. 2) bạn không cần phải sử dụng var để khai báo một biến. – Marius

Trả lời

14

Điều này không giống như các ngôn ngữ khác, JavaScript tạo tất cả các biến khi bắt đầu một hàm. Điều này có nghĩa rằng mã:

(function(){ 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     var myVar = 5; 
    } 
})(); 

là thực sự biên soạn và hiểu là

(function(){ 
    var myVar; 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     myVar = 5; 
    } 
})(); 

Để tạo một biến và chỉ có nó có sẵn bên trong một nếu hoặc chặn vòng lặp, bạn phải sử dụng let, đó là một tính năng JavaScript mới. Tôi không chắc chắn có bao nhiêu trình duyệt thực hiện nó (Firefox 3.5 hiện nếu bạn sử dụng <script type="text/javascript;version=1.7">).

(function(){ 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     let myVar = 5; 
    } 
})(); 
+0

Có, tôi biết điều này, hãy xem câu trả lời của tôi cho Amnon ở trên. Sự nhầm lẫn của tôi xuất phát từ thực tế là nó ảnh hưởng đến các cuộc gọi từ * trước khi nó được xác định trong phạm vi cục bộ *. – ELLIOTTCABLE

+0

Vâng, cuối cùng tôi đã hiểu câu hỏi của bạn và viết lại câu trả lời của tôi. Hi vọng điêu nay co ich. – Marius

+0

Vâng, điều đó đã giúp khá nhiều. Xem làm rõ của tôi trong câu hỏi ban đầu. Tôi thẳng thắn vẫn không thể hiểu tại sao điều này xảy ra theo cách của nó; Tôi cho rằng sự hiểu biết trực quan về JavaScript của tôi, ngôn ngữ, không phù hợp với đặc tả/triển khai. Bất kể, tôi sẽ đánh dấu câu trả lời này là ‘được chấp nhận’/= – ELLIOTTCABLE

1

việc bao gồm var có nghĩa là việc gán {} được thực hiện cho biến cục bộ xuất thay vì biến toàn cục xuất, có nghĩa là nó không có hiệu lực.

+0

Có. Điều đó tôi hiểu. Tôi * làm * biết JavaScript cơ bản. Vấn đề của tôi là vấn đề đến * sau * cuộc gọi mà chúng tôi đang xem xét; nó sẽ không ảnh hưởng đến việc có hay không 'xuất khẩu' là không xác định tại thời điểm gọi' alert() '. Bất kể điều gì xảy ra sau đó, 'xuất' là * không * không được xác định tại thời điểm đó. – ELLIOTTCABLE

2

var exports không hoạt động chính xác như biến cục bộ ở nhiều ngôn ngữ. Nó tuyên bố exports là biến cục bộ trong toàn bộ hàm thay vì chỉ khối bao quanh (mặc dù nó xuất hiện sau lần sử dụng đầu tiên), do đó, đối số hàm có cùng tên bị ẩn.

Chỉnh sửa: từ khóa let hoạt động bình thường hơn (nó chỉ khai báo biến cho khối chứa) nhưng không có sẵn trong tất cả các phiên bản của JavaScript.

+0

Vì vậy, thông dịch viên đọc trước, và thông báo việc khai báo biến ... và định nghĩa của biến trong phạm vi địa phương (gắn liền với 'undefined'), ghi đè đối số của đối số? Đó là * cực kỳ * phản trực giác. Làm thế nào để thông dịch viên đọc trước trong trường hợp này? o.O – ELLIOTTCABLE

+1

Có tính năng phản trực giác, nhưng đó là cách thực hiện ... Về cách thực hiện, chức năng được phân tích trước khi nó được chạy. – Amnon

+0

"" "Làm thế nào để thông dịch viên đọc trước trong trường hợp này?" "" - nó trông phía trước trong MỌI ví dụ. Nó không phải là "phân tích từng dòng" phân tích cú pháp/thông dịch viên như một số ngôn ngữ khác, trình phân tích cú pháp đọc TẤT CẢ các tập lệnh trước khi nó bắt đầu thực hiện bất kỳ thứ gì. – Hejazzman

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