2012-05-04 26 views
17

Giả sử tôi đang cố thực thi đoạn mã JavaScript này. Giả sử các phương thức và phương thức không khai báo được khai báo ở nơi khác, ở trên và rằng somethingsomethingElse đánh giá đúng boolean.Phạm vi JavaScript trong khối thử

try { 
    if(something) { 
     var magicVar = -1; 
    } 

    if(somethingElse) { 
     magicFunction(magicVar); 
    } 
} catch(e) { 
    doSomethingWithError(e); 
} 

Câu hỏi của tôi là: là những gì phạm vi magicVar và là nó không quan trọng để vượt qua nó vào magicFunction như tôi đã thực hiện?

+1

Dường như với tôi như thế này chỉ là một câu hỏi về phạm vi biến, không biến phạm vi trong một khối try. –

Trả lời

17

Javascript có phạm vi chức năng.Điều đó có nghĩa rằng magicvar sẽ tồn tại từ đầu hàm được khai báo trong tất cả các cách để kết thúc hàm đó, ngay cả khi câu lệnh đó không bao giờ thực thi. Đây được gọi là cẩu nâng. Điều tương tự cũng xảy ra với các khai báo hàm, lần lượt được gọi là chức năng cẩu.

Nếu biến được khai báo trong phạm vi toàn cầu, biến đó sẽ hiển thị với mọi thứ. Đây là một phần lý do tại sao các biến toàn cầu được coi là ác trong Javascript.

Ví dụ của bạn sẽ vượt qua undefined vào magicFunction nếu something là sai, bởi vì magicVar chưa được gán cho bất kỳ thứ gì.

Trong khi đây là Javascript hợp lệ về mặt kỹ thuật, nó thường được coi là kiểu xấu và sẽ không vượt qua bộ kiểm tra kiểu như jsLint. Vô cùng Javascript unintuitive như thế này sẽ thực thi mà không bất kỳ lỗi

alert(a); //alerts "undefined" 
var a; 

POP QUIZ: không đoạn mã sau làm gì?

(function() { 
    x = 2; 
    var x; 
    alert(x); 
})(); 
alert(x); 
+1

Ví dụ bạn đưa ra không phải là khá tốt bởi vì nó vẫn chưa được định nghĩa, vì 'window.a' là' undefined' – gdoron

+0

@gdoron Tôi không chắc tôi thấy bạn đang làm gì. Nếu bạn chỉ cố gắng chạy 'alert (a)' một mình, nó sẽ ném một lỗi như 'a is 'undefined''. –

+0

Điều này là 'a' _can_ không được xác định bởi vì nó không được xác định trong outerscope. Hãy xem [demo] này (http://jsfiddle.net/gdoron/H8c4n/3/) Nếu bạn loại bỏ 'var x' bạn vẫn nhận được kết quả tương tự. – gdoron

1

Với var, các biến tồn tại từ đầu hàm đến cuối của hàm, bất kể chúng được khai báo ở đâu hoặc thậm chí là câu lệnh có thực sự đạt được hay không. Tuy nhiên, chúng sẽ là undefined cho đến khi chúng được gán một giá trị khác.

Vì vậy, trong trường hợp của bạn, nếu something là sai nhưng somethingelse là đúng, bạn sẽ gọi magicFunction với đối số đầu tiên là undefined.

Các let từ khóa, tạo ra trong Javascript 1.9 và có sẵn (tính đến ngày hôm nay, ngày 03 tháng 5 thứ năm 2012, và như xa như tôi biết) chỉ trong Firefox, tuyên bố biến với ngữ nghĩa scoped lẽ bạn đã quen.

5
  • Trong các hàm chỉ javascript tạo ra một ngữ cảnh mới.
  • Mọi định nghĩa của một biến thực sự là một khai báo của biến ở trên cùng của phạm vi của nó và một nhiệm vụ tại nơi định nghĩa.

var

  • chức năng-scoped
  • tời lên đỉnh chức năng của nó
  • redeclarations cùng tên trong cùng một phạm vi không-ops

Bạn có thể muốn đọc MDN scope cheat sheet

Do hoisting Bạn thậm chí có thể làm những việc như thế này:

function bar() { 
    var x = "outer"; 

    function foo() { 
     alert(x); // {undefined} Doesn't refer to the outerscope x 
     // Due the the var hoising next:   
     x = 'inner'; 
     var x; 
     alert(x); // inner 

    } 
    foo(); 
} 

bar();​ 

bar();​ 

Demo

Vì vậy, các foo chức năng được chuyển thành một cái gì đó như thế này:

function foo() { 
    var x; 
    alert(x); // {undefined} Doesn't refer to the outerscope x 
    // Due the the var hoising next:   
    x = 'inner'; 
    alert(x); // inner 
}​ 

Câu hỏi của tôi là: phạm vi của magicVar an là bao nhiêu d có được phép chuyển nó vào magicFunction như tôi đã làm không?

Xác định okay ..., Có mã hợp lệ, nhưng ít đọc được hơn nếu các khai báo biến nằm ở trên cùng, đó là tất cả.

+0

Tôi bị rách! Tôi yêu cả bạn và Peter Olson. Có một upvote :) – user5243421

+0

@DarrenGreen. **:) ** Không cảm thấy xấu. Chỉ cần chọn câu trả lời tốt nhất mà bạn nghĩ bạn có. (Tôi không thích ý tưởng Stackoverflow chấp nhận câu trả lời bật lên đầu {Tôi có nghe thấy _hoisting_? :)} không, điều đó không có nghĩa là anh chàng có lẽ ít hiểu biết hơn về câu hỏi quyết định câu trả lời nào là tốt nhất .) Nếu đó là câu trả lời của Peter, tôi rất tuyệt với nó, tôi không cạnh tranh với câu trả lời. – gdoron

+0

Liên kết cheat sheet của bạn được coi là nội dung lỗi thời. Yêu các thanh cảnh báo lớn trên trang đó - bạn sẽ không bỏ lỡ điều đó! haha – jcollum

3

Do javascript "cẩu" (google nó), mã khai báo biến của bạn được dịch là:

function yourFunction() { 
    var magicVar; 
    try { 
     if(something) { 
      magicVar = -1; 
     } 

     if(somethingElse) { 
      magicFunction(magicVar); 
     } 
    } catch(e) { 
     doSomethingWithError(e); 
    } 

} //end of your function 

"tời kéo" di chuyển tất cả các tờ khai biến lên đỉnh của hàm. Vì vậy, magicVar có sẵn ở mọi nơi trong chức năng, nhưng nó không xác định cho đến khi bạn cung cấp cho nó một giá trị.

Biến của bạn có phạm vi chức năng.

14

Rất nhiều câu trả lời tốt khác về cách xử lý javascript này với var, nhưng tôi nghĩ rằng tôi muốn giải quyết tình hình let ...

Nếu một biến được định nghĩa với let bên trong khối try, nó sẽ không được trong phạm vi bên trong các khối catch (hoặc finally). Nó sẽ cần phải được định nghĩa trong khối bao quanh.

Ví dụ, trong khối mã sau đây, giao diện điều khiển đầu ra sẽ là "Bên ngoài":

let xyz = "Outside"; 

try { 
    let xyz = "Inside"; 

    throw new Error("Blah"); 
} catch (err) { 
    console.log(xyz); 
}