簡單瞭解JavaScript作用域
作用域通常是指在指定的時間內,變數存在於一段程式碼中。缺乏對作用域的理解可能會導致令人沮喪的除錯體驗。作用域的概念是關於我們的程式碼中可以訪問到哪些確定的函式或變數,程式碼的上下文和執行環境。
在 JavaScript 中,有兩種型別的作用域:全域性和區域性作用域。
全域性作用域
第一種作用域是全域性作用域。它很容易定義。如果一個變數或函式是_全域性的_,那麼在程式中的任何地方都可以訪問到它們。在瀏覽器中,全域性作用域是 window物件。如果在函式外面宣告一個變數,那麼這個變數就存在全域性物件中。例如:
var x = 9;
一旦該變數被定義,則可以被引用為 window.x,因為它存在於全域性物件中,我們可以簡單的引用它為 x。
區域性作用域
JavaScript 也可以在每個函式體中建立區域性作用域。例如:
function myFunc() { var x = 5; } myFunc(); console.log( x ); // ReferenceError: x is not defined
由於 x 是在 myFunc() 中初始化,所以它只能在 myFunc() 中被訪問,如果我們試圖在 myFunc() 外面訪問 x,則會得到一個引用錯誤。
注意
如果你忘記使用 var 關鍵字宣告變數,那麼這個變數會自動變成全域性變數。所以這段程式碼可以執行:
function myFunc() { x = 5; } myFunc(); console.log( x ); // 5
這是一個壞主意。全域性變數的值可以被程式的任何部分或者其他指令碼更改。這是不期望發生的,因為它會導致無法預料的副作用。
立即呼叫表示式(IIFE)提供了一個避免全域性變數的方式。你會看到許多如 jQuery 的 JavaScript 庫經常使用這種方式:
(function() { var jQuery = { /* All my methods go here. */ }; window.jQuery = jQuery; })();
將一切包含在一個函式中並立即呼叫這個函式,這意味著函式中的所有變數都被繫結在_區域性作用域_中。在函式結尾部分,你可以通過將 jQuery 物件繫結在全域性物件 window 上,將一些方法和屬性公開出來。瞭解更多關於立即呼叫函式表示式,請檢視 Ben Alman 的文章 Immediately-Invoked Function Expression。
因為區域性作用域通過函式而工作,任何在另一個函式中定義的函式都可以訪問外部函式裡的變數:
function outer() { var x = 5; function inner() { console.log( x ); } inner(); // 5 }
但是 .outer() 函式不能訪問 .inner() 函式中定義的任何變數。
function outer() { var x = 5; function inner() { console.log( x ); var y = 10; } inner(); // 5 console.log( y ); // ReferenceError: y is not defined }
另外,在一個函式中沒有使用 var 關鍵字定義的變數不是這個函式的區域性變數 - JavaScript 會向上遍歷作用域鏈(最後會到 window 物件)尋找之前定義的這個變數。如果這個變數沒有定義,則會在全域性中定義該變數,這樣會導致意外的結果。
// Functions have access to variables defined in the same scope. var foo = "hello"; var sayHello = function() { console.log( foo ); }; sayHello(); // "hello" console.log( foo ); // "hello"
相同名稱的變數可以在不同作用域中儲存不同的值:
var foo = "world"; var sayHello = function() { var foo = "hello"; console.log( foo ); }; sayHello(); // "hello" console.log( foo ); // "world"
當在一個函式中引用一個外部作用域定義的變數,函式可以訪問在該函式定義之後發生改變的變數值。
var myFunction = function() { var foo = "hello"; var myFn = function() { console.log( foo ); }; foo = "world"; return myFn; }; var f = myFunction(); f(); // "world"
這是一個更復雜的作用域例子:
(function() { var baz = 1; var bim = function() { console.log( baz ); }; bar = function() { console.log( baz ); }; })();
在這個例項中,執行:
console.log( baz ); // baz is not defined outside of the function
將會得到一個 ReferenceError。baz 僅僅是在函式中定義,並且沒有暴露在全域性作用域中。
bar(); // 1
.bar() 是在匿名函式中定義的, 但是它沒有使用 var 關鍵字定義,這意味著它沒有繫結到區域性作用域,而是在全域性作用域建立。另外,它可以訪問 baz 變數,因為 .bar() 是在與 baz 相同的作用域定義的,所以它可以訪問變數 baz,即使函式外部的其他程式碼不可以。
bim(); // ReferenceError: bim is not defined
.bim() 只在函式中定義的,所以它作為區域性變數而不存在於全域性物件中。
以上就是簡單瞭解JavaScript作用域的詳細內容,更多關於JavaScript作用域的資料請關注我們其它相關文章!