JS作用域鏈
當代碼在一個環(huán)境中執(zhí)行時矗蕊,會創(chuàng)建變量對象的一個作用域鏈來保證對執(zhí)行環(huán)境有權訪問的變量和函數的有序訪問。
在作用域鏈的前端始終都是當前執(zhí)行的代碼所在的執(zhí)行環(huán)境的變量對象(這個環(huán)境如果是函數,會把它的活動對象作為變量對象,活動對象最開始只包含一個變量,也就是arguments對象),作用域鏈中的下一個變量對象來自外部包含環(huán)境闻妓,在下一個變量對象時來自下一個包含環(huán)境一直延伸到全局執(zhí)行環(huán)境,即全局執(zhí)行環(huán)境始終都是作用域鏈的最后一個對象掠械。
例1:
var test = 'Hello';
function f() {
if(test == 'Hello') {
test = 'hi';
}
else {
test = 'Hello';
}
}
f();
console.log(test);
//輸出:hi
變量名的解析的過程實際就是沿著作用域鏈一層一層搜索標識符的過程由缆,開始是從作用域鏈的前端進行注祖,然后逐級向后直至找到為止。
例如:在上面這個小例子中函數f()的作用域上有兩個對象均唉,一個是自己的變量對象是晨,一個就是全局環(huán)境的變量對象,當在函數中使用test變量時會先從作用域鏈的前端舔箭,也就是當前執(zhí)行環(huán)境尋找罩缴,沒有找到,會往后倒全局執(zhí)行環(huán)境中尋找层扶,而test變量是在全局執(zhí)行環(huán)境中定義的箫章,所以會在全局執(zhí)行環(huán)境中找到這個變量(如果沒有找到,證明這個標識符未被定義镜会,瀏覽器會Uncaught ReferenceError)檬寂。
例2:
var test = 'test';
function f() {
var anotherTest = 'another';
function f2() {
var tempTest = 'temp';
anotherTest = test;
test = tempTest;
//這里可以訪問test和anotherTest和tempTest
}
//這里可以訪問test和anotherTest,不能訪問tempTest
f2();
}
//這里只能訪問test
f();
通過上面的例子可以說明戳表,內部環(huán)境可以通過作用域訪問所有的外部環(huán)境桶至,但是外部環(huán)境不能訪問內部環(huán)境中的任何變量和函數,每個環(huán)境都可以向上搜索作用域鏈扒袖,但任何環(huán)境都不能通過向下搜索作用域鏈而進入另一個環(huán)境塞茅。這樣也就解釋了上面我們所說的如果局部環(huán)境中存在同名的標識符,那么會覆蓋全局變量季率。