什么是作用域?
這篇文章引用了《高性能JavaScript》這本書中一些作用域的知識,有興趣的朋友可以看一看。
既然是JS基礎類別的,自然就少不了JS作用域的知識。js中的作用域分為全局作用域和局部作用域。js中並沒有 像java語言中的塊級作用域。
全局作用域
var a = 0;
if (true) {
var b = 1;
}
console.log(b); // 輸出1
像這樣在全局中定義a
變量,為全局變量,在任何地方都能訪問到這個a
變量。
因為js中沒有塊級作用域,所以在 if
或是 for
這樣邏輯語句中定義的變量都是可以被外界訪問到的。
局部作用域
局部作用域也可以稱之為函數作用域。
function fn () {
var c = 2;
}
console.log(c); // 報錯,c變量未定義
局部作用域中定義的變量,只供局部作用域調用,外界無法訪問。
作用域鏈
Function對象有一個僅供 JavaScript 引擎存取的內部屬性。
這個屬性就是[[Scope]]
。[[Scope]]
包含了一個函數被創建的作用域中對象的集合。這個集合被稱為函數的作用域鏈,它決定了哪些數據能被函數訪問。
關於作用域鏈,局部作用域可以訪問到全局作用域中的變量和方法,而全局作用域不能訪問局部作用域的變量和方法。
var a = 0;
function fn () {
var b = 1;
console.log(a); // 輸出 1
}
// 全局作用域並不能訪問 fn 函數中定義的 b 變量
console.log(b); // 報錯
fn();
當函數fn()
創建時,它的作用域中插入了一個對象變量,這個全局對象代表所有在全局范圍內定義的變量。
當函數fn()
執行時,會創建一個名為執行環境的獨一無二的內部對象。函數每執行一次,都會創建一個執行環境。當函數執行完畢,執行環境就會被銷毀。
每個執行環境都有自己的作用域鏈,用來解析標識符。當執行環境被創建時,它的作用域就會初始化為當前運行函數的[[Scope]]
屬性中的對象。
執行環境創建完成之后,就會生成一個"活動對象"
,這個對象包含了當前函數的所有局部變量
,命名參數
,參數集合
和this
。此對象會被推入作用域鏈的最前端。
當執行環境被銷毀后,"活動對象"
也會隨之被銷毀。
如下圖所示:
當fn()
時,會使用到a
變量,這時候就會搜索執行環境的作用域鏈,找到就使用,找不到就會到作用域鏈的下一個對象找,如果搜尋到最后,還沒找到,那就認定這個變量是未定義的。