JavaScript作用域
1.作用域
JavaScript的作用域與C、Java等語(yǔ)言不同,它不是以花括號(hào)包圍的塊級(jí)作用域,這個(gè)特性經(jīng)常被大多數(shù)人忽視。例如下面代碼,在大多數(shù)類(lèi)C的語(yǔ)言中會(huì)出現(xiàn)變量未定義的錯(cuò)誤,但在JavaScript中卻完全合法:
if (true) {
? ? ? var msg = 'msg';
}
console.log(msg); // 輸出 msg;
這是因?yàn)镴avaScript的作用域完全是由函數(shù)來(lái)決定的,if、for語(yǔ)句中的花括號(hào)不是獨(dú)立的作用域。
2.函數(shù)作用域
不同于大多數(shù)類(lèi)C的語(yǔ)言,由一對(duì)花括號(hào)封閉的代碼塊就是一個(gè)作用域,JavaScript的作用域是通過(guò)函數(shù)來(lái)定義的,在一個(gè)函數(shù)中定義的變量只對(duì)這個(gè)函數(shù)內(nèi)部可見(jiàn),我們稱(chēng)為函數(shù)作用域。在函數(shù)中引用一個(gè)變量時(shí),JavaScript會(huì)先搜索當(dāng)前函數(shù)作用域,如果沒(méi)有找到則搜索其上層作用域,一直到全局作用域。下面是一個(gè)簡(jiǎn)單的例子:
var scope = 'global';
var f1 = function() {
? ? ? ?console.log(scope);
}
f1(); // 輸出 global
var f2 = function() {
var scope = 'f2';
? ? ?console.log(scope);
}
f2(); // 輸出 f2
以上示例十分明了,JavaScript的函數(shù)定義是可以嵌套的,每一層是一個(gè)作用域,變量搜索順序是從內(nèi)到外,按照作用域搜索順序,在console.log函數(shù)訪問(wèn)scope變量時(shí),JavaScript會(huì)先搜索函數(shù)f2的作用域,恰巧在f2的作用域里搜索到了scope變量,所以上層作用域中定義的scope就被屏蔽了。但下面這個(gè)例子可能就有些讓人困惑:
var scope = 'global';
var f3 = function() {
console.log(scope);
var scope = 'f3';
}
f3(); // 輸出 undefined
復(fù)制代碼
上面的代碼可能和你的預(yù)想不一樣,并沒(méi)有輸出global,而是undefined,這是為什么吶?這是JavaScript的一個(gè)特性,就是變量聲明語(yǔ)句永遠(yuǎn)在該作用域里最先被執(zhí)行,所以上面的例子形同如下:
var scope = 'global';
var f4 = function() {
var scope; // 變量聲明最先被執(zhí)行
console.log(scope);
scope = 'f4'; //變量被賦予值
}
f4(); // 輸出 undefined
這樣就不難理解運(yùn)行f3()函數(shù)為什么沒(méi)輸出global,而是undefined了。
3.函數(shù)作用域的嵌套
一個(gè)作用域嵌套的例子:
var f5 = function() {
var scope = 'first';
(function() {
var scope = 'second';
(function() {
console.log(scope);
}());
}());
}
f5(); // 輸出 second
我們?cè)谧顑?nèi)層函數(shù)中引用到了scope變量,通過(guò)作用域搜索,找到了其父作用域中定義的scope變量。
有一點(diǎn)要注意:函數(shù)作用域的嵌套關(guān)系是在定義時(shí)決定的,而不是在調(diào)用時(shí)決定的,下面是一個(gè)簡(jiǎn)單的例子:
var scope = 'global';
var f6 = function() {
console.log(scope);
}
var f7 = function() {
var scope = 'f7';
f6();
}
f7(); // 輸出 global
這個(gè)例子中,通過(guò)f7調(diào)用的f6在搜索scope時(shí),找到的是f6函數(shù)的父作用域中定義的scope變量,而不是f7中定義的scope變量。這說(shuō)明了函數(shù)作用域的嵌套關(guān)系是在定義時(shí)決定的,而不是在調(diào)用時(shí)決定的。