我還記得之前很長一段時間被各種作用域面試題支配的恐懼(弱小無助.png)
現(xiàn)在不怕啦弓乙,讀懂作用域先理解預(yù)編譯。
來道簡單題先:
var a="aa";
function test(){
console.log(a);
var a="bb";
console.log(a);
}
test();
console.log(a);
答案:undefined bb aa
幾個概念解釋下:
預(yù)編譯
javascript是解釋性語言剑梳,主要特點為解釋一行執(zhí)行一行唆貌。而在js運行時會進行三件事:
1語法分析
2.預(yù)編譯
3.解釋執(zhí)行
語法分析會在代碼執(zhí)行前對代碼進行通篇檢查,以排除一些低級錯誤垢乙,預(yù)編譯發(fā)生在代碼執(zhí)行的前一刻锨咙。所以,函數(shù)在執(zhí)行時已經(jīng)預(yù)編譯過了追逮。
頁面在創(chuàng)建之初就創(chuàng)建了GO(global object)對象酪刀,即window對象,所以全局變量也可以叫做window的屬性钮孵。
1骂倘、查找變量,作為GO屬性巴席,并賦值undefined历涝。
2、查找函數(shù)聲明體,作為GO屬性荧库,并賦值函數(shù)體堰塌。
預(yù)編譯做了些什么事情
1、查看語法錯誤分衫,如果有錯誤就不執(zhí)行接下來的代碼场刑。
2、發(fā)現(xiàn)有調(diào)用函數(shù)時蚪战,創(chuàng)建AO(activation object)對象牵现。
3、查找形參和變量聲明邀桑,將變量和形參名作為AO屬性名瞎疼,值為undefined
4、將實參值和形參統(tǒng)一
5概漱、在函數(shù)體里面找函數(shù)聲明丑慎,值賦予函數(shù)體
現(xiàn)在回到剛才的那道題:
1、創(chuàng)建了GO對象
GO{
a:undefined, //查找變量瓤摧,作為GO屬性竿裂,并賦值undefined
test:fun, //查找函數(shù)聲明體,作為GO屬性照弥,并賦值函數(shù)體
}
2腻异、執(zhí)行js
GO{
a:"aa", //變量a已存在,賦值‘a(chǎn)a’
test:fun,
}
3这揣、讀到函數(shù)調(diào)用悔常,創(chuàng)建test函數(shù)的AO對象
AO{
a:undefined, //查找變量,作為AO屬性给赞,賦值undefined
}
4机打、執(zhí)行test 函數(shù)
console.log(a) //undefined
此時有2個同名為a的變量,這里涉及到作用域鏈[[scope]]的概念片迅,但是只要記住残邀,自己有的用自己的,沒有的再向父級尋找柑蛇。
此時芥挣,test函數(shù)AO對象內(nèi)有a,且值為undefined耻台,所以打印出來為undefined,
AO{
a:“bb”, //var a = 'bb'給a賦值
}
5空免、函數(shù)執(zhí)行完畢
console.log(a); // ‘bb’此時的a為全局變量a,父級不能訪問子級的私有變量
再來幾道題盆耽,大家可以把答案寫在下面:
var fn
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){}
console.log(a);
var b = function (){}
console.log(b);
function d(){}
}
fn(1)
console.log(fn)
function test (a,b){
console.log(a)
c = 0;
var c;
a = 3;
b =2;
console.log(b);
function b() {}
function d() {}
console.log(b)
}
test(1)
console.log(test);
function test(test){
console.log(test);
var test = 123
console.log(test)
function test (){}
}
test(1);
var test = 123
沒有聲明的變量賦值蹋砚,默認(rèn)為全局變量扼菠,不管在哪里都默認(rèn)為全局變量。