2019-11-18 seo達(dá)人
JS----預(yù)編譯及變量提升詳解
JS屬于解釋型語言,在執(zhí)行過程中順序執(zhí)行,但是會分塊先預(yù)編譯然后才執(zhí)行。因此在JS中存在一種變量提升的現(xiàn)象。搞懂預(yù)編譯環(huán)節(jié),變量提升自然而然也就懂了。本文講圍繞以下幾點進(jìn)行介紹(變量提升會穿插在其中講解):
預(yù)編譯執(zhí)行步驟
示例演示
預(yù)編譯執(zhí)行步驟
預(yù)編譯發(fā)生在函數(shù)執(zhí)行的前一刻,過程如下:
創(chuàng)建AO對象,執(zhí)行期上下文(后面更新關(guān)于執(zhí)行期上下文詳解)。
尋找函數(shù)的形參和變量聲明,將變量和形參名作為AO對象的屬性名,值設(shè)定為undefined.
將形參和實參相統(tǒng)一,即更改形參后的undefined為具體的形參值。
尋找函數(shù)中的函數(shù)聲明,將函數(shù)名作為AO屬性名,值為函數(shù)體。
至此,預(yù)編譯環(huán)節(jié)結(jié)束,函數(shù)中咯變量按照最終AO對象中的值開始執(zhí)行。接下來,結(jié)合示例演示就會更加清晰。
作者:北海北方
鏈接:https://juejin.im/post/5aa6693df265da23884cb571
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
示例演示
我們先來看下面這段代碼:
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(){};
}
//調(diào)用函數(shù)
fn(1);
作者:北海北方
鏈接:https://juejin.im/post/5aa6693df265da23884cb571
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
接下來我們來按照前面的步驟詳細(xì)分析它的預(yù)編譯執(zhí)行過程:
創(chuàng)建AO對象
AO{
//空對象
}
復(fù)制代碼
找形參和變量聲明
AO{
a : undefined,
b : undefined
}
復(fù)制代碼
形參和實參相統(tǒng)一
AO{
a : 1,
b : undefined
}
復(fù)制代碼
找函數(shù)聲明
AO{
a : function a(){},
b : undefined,
d : function d(){}
}
復(fù)制代碼預(yù)編譯環(huán)節(jié)就此結(jié)束,此時的AO對象已經(jīng)更新為:
AO{
a : function a(){},
b : undefined,
d : function d(){}
}
復(fù)制代碼函數(shù)開始逐行順序執(zhí)行:
function fn(a){
console.log(a);// 輸出functiona(){}
var a = 123;//執(zhí)行到這里重新對a賦,AO對象再一次更新
console.log(a);// 輸出123
function a(){};//預(yù)編譯環(huán)節(jié)已經(jīng)進(jìn)行了變量提升,故執(zhí)行時不在看這行代碼
console.log(a);// 輸出123
var b = function(){};//這個是函數(shù)表達(dá)式不是函數(shù)聲明,故不能提升,會對AO中的b重新賦值
console.log(b);//輸出function(){}
function d(){};
}
復(fù)制代碼至此,函數(shù)執(zhí)行完畢,銷毀AO對象。
我們再來看幾個例子,熟悉函數(shù)的預(yù)編譯過程。
示例一:
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);
}
//調(diào)用函數(shù)
test(1);
復(fù)制代碼它的AO創(chuàng)建過程如下(此處省略創(chuàng)建空AO對象的部分,下文同):
AO1{
a : undefined,
b : undefined,
c : undefined
}
AO2{
a : 1,
b : undefined,
c : undefined
}
AO3{
a : 1,
b : function b(){},
c : undefined,
d : function d(){}
}
復(fù)制代碼至此預(yù)編譯環(huán)節(jié)完成,開始執(zhí)行:
function test (a,b){
console.log(a); //輸出1
c = 0; //給AO對象中的c重新賦值0
var c;//預(yù)編譯環(huán)節(jié)變量提升,不再讀此行代碼
a = 3;//給AO對象中的a重新賦值3
b = 2;//給AO對象中的b重新賦值2
console.log(b);//輸出2
function b(){};//預(yù)編譯環(huán)節(jié)變量提升,執(zhí)行時不再讀這行代碼
function d(){};//預(yù)編譯環(huán)節(jié)變量提升,執(zhí)行時不再讀這行代碼
console.log(b);//輸出2
}
//調(diào)用函數(shù)
test(1);
復(fù)制代碼示例二:
這個例子中我們引入全局對象GO。GO與AO的過程類似
function test(){
var a = b = 123;
}
test();
復(fù)制代碼此函數(shù)的執(zhí)行過程:先把123賦給b,再聲明a,再把b賦給a。此時變量b未經(jīng)聲明就賦值,為全局變量。預(yù)編譯環(huán)節(jié)如下:
GO1{
b : undefined
}
AO1{
a : undefined
}
GO2{
b : 123;
}
AO2{
a : 123;
}
復(fù)制代碼示例三 :
console.log(test);
function test(test){
console.log(test);
var test = 234;
console.log(test);
function test(){};
}
test(1);
var test = 123;
復(fù)制代碼我們來看它的預(yù)編譯過程:
//執(zhí)行前(頁面加載完成時)生成GO對象
GO1{
test : undefined
}
GO2{
test : function(){}
}
//輸出 function test(){...}
//執(zhí)行test()前生成它的AO對象
AO1{
test : undefined
}
AO2{
test : 1
}
AO3{
test : function test(){}
}
//預(yù)編譯結(jié)束開始執(zhí)行test(1);
AO4{
test : 234
}
//輸出234
復(fù)制代碼示例四:
function demo(){
console.log(b);
if(a){
var b = 100;
}
console.log(b);
c = 234;
console.log(c);
}
var a;
demo();
a = 10;
console.log(c);
復(fù)制代碼我們來看它的預(yù)編譯過程:
//首先是全局對象GO
GO1{
a : undefined
}
G02{
a : undefined,
demo : function demo(){}
}
//執(zhí)行demo()前預(yù)編譯,由于demo中的c未聲明就使用故為全局對象
//輸出undefined
GO3{
a : undefined,
demo : function demo(){}
c : undefined
}
//此時a還是undefined,故不執(zhí)行if()代碼塊
//輸出還是undefined
GO4{
a : undefined,
demo : function demo(){}
c : 234;
}
//輸出234
GO5{
a : 10,
demo : function demo(){}
c : 234;
}
//輸出234
藍(lán)藍(lán)設(shè)計的小編 http://www.wnxcall.com