1. 程式人生 > >JS的解析與執行過程—(全局預處理階段)

JS的解析與執行過程—(全局預處理階段)

調用 ont err col 過程 預處理 報錯 彈出 error:

問題:有如下代碼

1 var a = 1;
2 function pop() {
3     alert(a);
4     var a = 5;
5 }
6 pop();//執行結果,彈出undefined

這段代碼的執行結果為undefined,為什麽呢?

JS的解析與執行並不是讀一行,處理一行,讀一行,處理一行這樣進行的,而是分為兩個階段:

1、預處理階段;

2、執行階段;

然後分別以全局和函數內部的局部代碼而言:

1、全局預處理

在解析JS代碼的時候,首先會創建一個全局LexicalEnviroment{ }(詞法環境)對象

接下來掃描JS代碼裏面的兩個部分:

a、用聲明的方式創建的函數;

b、用var定義的變量;

掃面完畢後將這些變量及函數添加到全局的詞法環境對象裏面去;

 1 LexicalEnviroment: {
 2     a: undefined,
 3     b: undefined,
 4     test: 對函數的一個引用
 5 }
 6 
 7 //用聲明的方式創建的函數
 8 function test(params) {
 9     
10 }
11 //用函數表達式創建的函數
12 var test1 = function(params) {
13     
14 }
15 //用var定義的變量
16 var a = 5; 17 var b; 18 //其他變量 19 c = 6;

定義一個聲明函數和一個函數表達式來證明這一點,代碼如下:

1 f();
2 g();
3 
4 function f() {
5     console.log("ff");
6 }
7 var g = function() {
8     console.log("gg");
9 }

得到如下結果:

1 ff
2 e:\Code\JavaScript\day03\test2.js:2
3 g();
4 ^
5 
6 TypeError: g is not a function

函數f被正常執行,而函數g報錯了

因為在預處理階段,函數f的引用被放在LexicalEnviroment對象中了,而g沒有,所以在調用時函數g()並不存在,所以報錯。

改一下位置,這樣就對了

1 f();
2 var g = function() {
3     console.log("gg");
4 }
5 g();
6 
7 function f() {
8     console.log("ff");
9 }

這點在var定義變量上的體現:

1 console.log(a);
2 console.log(b);
3 
4 var a = 5;
5 b = 6;

這段代碼的執行結果如下:

1 undefined
2 e:\Code\JavaScript\day03\test3.js:2
3 console.log(b);
4             ^
5 
6 ReferenceError: b is not defined

可見,如上所說,以var方式定義的a被添加到全局LexicalEnviroment{ }(詞法環境)對象中了,其值為undefined,而直接定義的b此時不存在,所以報錯。

這就是全局預處理階段的過程。

聲明:

關於全局的詞法環境對象LexicalEnviroment,在瀏覽器中就約等於window對象,該對象是屬於JS解析器的東西,在不同的地方叫法不同,比如在Node中稱為Execute Context(運行上下文對象)或許更合適一點,在ECMA -262標準中有其解釋,但我們無需關心其具體含義,只是有這個概念便可。

JS的解析與執行過程—(全局預處理階段)