題目如下:
var x = 10;
function fn(){
? ? console.log(x);
}
function show(f){? ??
? ? var x = 20;
? ? (function () {
? ? ? ? f();
? ? })();
}
show(fn);
從題目可以看出,這里在全局和函數(shù)內(nèi)部聲明了兩個同名的x變量李命。函數(shù)show內(nèi)部還有一個立即執(zhí)行函數(shù)党觅。其實這些都是煙霧彈框冀,這道題其實是主要想考查阅爽,我們對于作用域鏈的理解汤锨,下面我們來分析下:
1.首先在全局范圍內(nèi)类溢,聲明了兩個函數(shù) fn,show和一個x變量钥飞,全局環(huán)境執(zhí)行莺掠,導(dǎo)致fn的定義,定義后读宙,函數(shù)fn的作用域鏈上就拿到了父環(huán)境的作用域鏈彻秆,簡單點說,fn現(xiàn)在的作用域鏈上只有一個全局global對象结闸,而global對象上只有兩個函數(shù)唇兑,一個x變量。
2.聲明階段完成后桦锄,在全局環(huán)境下扎附,調(diào)用了show這個函數(shù),并且把函數(shù)fn這個函數(shù)的引用當(dāng)成實參傳進(jìn)了show函數(shù)體內(nèi)结耀。
3.show函數(shù)體內(nèi)留夜,同樣聲明了一個x變量匙铡,但是這個x其實是添加到show函數(shù)的作用域上,還聲明了一個立即執(zhí)行函數(shù)碍粥,在立即執(zhí)行函數(shù)中慰枕,執(zhí)行了fn的引用。fn執(zhí)行會生成自己的活動對象(Active Object)即纲,并將自己的活動對象放在作用域的第一位。這個時候fn函數(shù)的作用域鏈就是AO(fn)-->GO(Global Obect)博肋。
4.函數(shù)執(zhí)行時低斋,查找作用鏈上是否有訪問的變量,都是順著作用域鏈查起匪凡,也就是說從自己的AO查起膊畴,到GO結(jié)束。當(dāng)然有些特殊用法病游,也有意外,比如with的用法唇跨。從上面的例子可以看出,函數(shù)fn的作用域鏈和show的作用域鏈基本上沒關(guān)系衬衬。所以也就訪問不到show內(nèi)部聲明的變量x买猖,fn打印的其實就是全局聲明的x。
5.最后說明一下滋尉,這里放在立即執(zhí)行函數(shù)內(nèi)玉控,只是一個煙霧彈,刪掉立即執(zhí)行函數(shù)也不會改變fn的作用域的狮惜,打印的結(jié)果同樣是10高诺。
var x = 10;
function fn(){
? ? console.log(x);
}
function show(f){
? ? var x = 20;
? ? f();
}
show(fn);
6.最后,再佐證下碾篡,fn和show的作用域沒關(guān)系虱而。這里在show內(nèi)聲明了一個m,如果fn和show的作用域有關(guān)系开泽,打印m牡拇,應(yīng)該可以打印出10,事實上沒有找到m眼姐。
var x = 10;
function fn(){
console.log(m);
}
function show(f){
? ? var x = 20;
? ? var m = 10;
? ? (function () {
? ? ? ? f(m);
? ? })();
}
show(fn);
結(jié)果: