概述
在文章最開始,先學習幾個概念:
- 作用域:
中指出,作用域是一套規則,這套規則用來管理引擎如何在目前作用域以及嵌套的子作用域中根據辨別符名稱進行變量查找。簡單來說,作用域規定了如何查找變量。《你不知道的js》
- 靜态作用域:又稱詞法作用域,是指作用域在此法階段就被确定了,不會改變。
- 動态作用域:函數的作用域在函數調用時才決定的。
靜态作用域與動态作用域
JavaScript
采用的是詞法作用域,函數定義的位置就決定了函數的作用域。
具體看一個例子:
var val = 1;
function test() {
console.log(val);
}
function bar() {
var val = 2;
test();
}
bar();
// 結果是???
最終的輸出結果是
1
,說明
test
列印的是全局下的
val
,這也印證了
JavaScript
使用了靜态作用域。
在學習詞法作用域之前,已經學習了作用域鍊和預編譯過程,雖然有幾分本末倒置,但是對詞法的了解還是有一定幫助。
靜态作用域執行過程
當函數執行
test
函數時,先從内部的
AO
對象查找是否有
val
對象,如果沒有,沿着作用域鍊往上查找(由于
JavaScript
是詞法作用域),上層為全局
GO
,是以結果列印
1
動态作用域執行過程
但如果
JavaScript
采用的動态作用域,執行
test
函數,從函數内部查詢
val
變量,如果沒有,就調用函數的作用域,即
bar
函數的作用域,成功查詢到
val=2
思考題
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
很明顯,兩個都列印
local scope
,
JavaScript
采用詞法作用域,上述兩個函數都定義在
checkscope
中,是以當
f()
函數執行時,首先查詢自身作用域是否有
scope
變量,如果沒有,它們的上級作用域都是
checkscope
,是以輸出
local scope
。
對此
《JavaScript權威指南》
解釋到:
JavaScript
函數的執行用到了作用域鍊,這個作用域鍊是在函數定義的時候建立的。嵌套的函數
f()
定義在這個作用域鍊裡,其中的變量
scope
一定是局部變量,不管何時何地執行函數
f()
,這種綁定在執行
f()
時依然有效。
如果想更深入、更透徹的了解上面的知識,建議深入學習作用域鍊和預編譯的知識。
參考部落格:JavaScript深入之詞法作用域和動态作用域