JS面向?qū)ο缶幊?1- 預(yù)處理與執(zhí)行階段

理論知識

JavaScript是一種描述型的腳本語言,它不同于java或C#等編譯性語言,它不需要進(jìn)行編譯成中間語言,而是由瀏覽器進(jìn)行動態(tài)地解析與執(zhí)行。所以理解javaScript語言的運(yùn)行機(jī)制,掌握javascript的執(zhí)行順序,有利于我們學(xué)好JavaScript。

預(yù)處理階段

js在預(yù)處理階段,創(chuàng)建一個詞法環(huán)境(LexicalEnvironment),掃描JS中的用聲明的方式聲明的函數(shù)用var定義的變量并將它們加到預(yù)處理階段的詞法環(huán)境中去。掃描順序:先掃描函數(shù)聲明,再掃描變量聲明

用var定義的變量:undefined;

聲明的函數(shù): 對函數(shù)引用

其中遇到命名沖突時,處理原則為:

1.處理函數(shù)聲明有沖突時,會覆蓋;

2.處理變量聲明有沖突時,會忽略

執(zhí)行階段

在執(zhí)行階段中,js會先掃描函數(shù)聲明后掃描變量,然后給預(yù)處理階段中執(zhí)行上下文對象中的成員賦值,如果沒有用var聲明的變量,會成為最外部執(zhí)行上下文的成員。

全局

全局預(yù)處理階段

比如說下面的這段代碼:
<pre>
var a = 1;//用var定義的變量,以賦值
var b;//用var定義的變量,未賦值
c = 3;//未定義,直接賦值
function d(){//用聲明的方式聲明的函數(shù)
console.log('hello');
}
var e = function(){//函數(shù)表達(dá)式
console.log('world');
}
</pre>
在預(yù)處理時,創(chuàng)建的作用域標(biāo)示為:

<pre>

LE{
a:undefined
b:undefined
沒有c
d:對函數(shù)引用
沒有e
}

</pre>

Note
一定區(qū)分 聲明式的函數(shù)函數(shù)表達(dá)式 概念

命名沖突的處理

<pre>
console.log(f);
var f = 1;
function f(){
console.log('foodoir');
}
</pre>

輸出結(jié)果:function f(){console.log('foodoir');}

<pre>
console.log(f);
function f(){
console.log('foodoir');
}
var f = 1;
</pre>

輸出結(jié)果:function f(){console.log('foodoir');}

<pre>
console.log(f);
var f = 1;
var f = 2;
console.log(f);
</pre>

輸出結(jié)果:先undefined 后 2

總結(jié)一句話:函數(shù)是js里的第一等公民

全局

全局執(zhí)行階段

<pre>
1 console.log(a);
2 console.log(b);
3 console.log(c);
4 console.log(d);
5 var a = 1;
6 b = 2;
7 console.log(b);
8 function c(){
9 console.log('c');
10 }
11
12 var d = function(){
13 console.log('d');
14 }
15 console.log(d);
</pre>

1.首先我們先進(jìn)行與處理階段分析
<pre>
LE{
a:undefined
沒有b
c:對函數(shù)的一個引用
d:undefined
}
</pre>

結(jié)果:
<pre>
此時,我們可以得到前四行代碼得到的結(jié)果分別為:
  undefined
  報錯
  function c(){console.log('c');
  undefined
</pre>

2、當(dāng)執(zhí)行完預(yù)處理后,代碼開始一步步被解析(將第二行報錯的代碼注釋掉)
<pre>
LE{
a:1
b:2
c:指向函數(shù)
d:指向函數(shù)
}
</pre>

其中變量b比較特殊,變?yōu)榱?strong>最外部執(zhí)行上下文的成員

函數(shù)

函數(shù)預(yù)處理階段

函數(shù)在預(yù)處理階段與全局的基本一致,函數(shù)中有個arguments

  • 每調(diào)用一次,產(chǎn)生一個詞法環(huán)境(或執(zhí)行上下文Execution Context);
  • 先傳入函數(shù)的參數(shù),若參數(shù)值為空,初始化undefined;
  • 然后是內(nèi)部函數(shù)聲明,若發(fā)生命名沖突,會覆蓋;
  • 接著就是內(nèi)部var變量聲明,若發(fā)生命名沖突,會忽略;

讓我們來看下面的例子

<pre>
function f(a,b){
alert(a);
alert(b);

var b = 100;
function a(){}

}
f(1,2);

</pre>

我們先來分析函數(shù)的預(yù)處理,它和全局的預(yù)處理類似,它的詞法結(jié)構(gòu)如下:

<pre>
LE{
b:2
a:指向函數(shù)的引用
arguments:2
}
//arguments,調(diào)用函數(shù)時實際調(diào)用的參數(shù)個數(shù)

</pre>

再結(jié)合之前的那句話:處理函數(shù)聲明有沖突時,會覆蓋;處理變量聲明時有沖突,會忽略。
故結(jié)果分別為:function a(){}和2

其中有兩種特殊情況
1.實際參數(shù)少于形參,
f(1)

這個時候語法結(jié)構(gòu)
<pre>

LE{
b:undefined
a:對函數(shù)的一個引用
arguments:1
}
故結(jié)果分別為:function a(){}和undefined
</pre>
2.沒有用var聲明的變量

<pre>
function a(){
function b(){
g = 12;
}
b();
}
a();
console.log(g);//12
</pre>

如果沒有用var聲明的變量,會變成最外部LE的成員,即全局變量

函數(shù)執(zhí)行階段
  • 給預(yù)處理階段的成員賦值;
  • 無var聲明的變量,會成為全局成員;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容