JS同名時var 和 function執行順序的問題?

例1:

var a ;

alert( a );

function a(){};

//輸出function a(){};

例2:

function a(){};

var a;

alert(a);

//輸出function a(){};

首先不應該是頁面載入完後function先執行,然後在var 重新定義a嗎 為什麼不管function a(){}怎麼放 a的值永遠都是function a(){};

難道我對var的認知出問題了么。。。


是的,當你問出這樣的問題,說明你不了解JavaScript中var聲明和函數聲明的機制。

為了能夠用比較簡單的話語回答這個問題,我就不牽扯太多規範中的專業名字定義了。我假設你應該至少知道執行上下文的概念

JavaScript執行代碼,我這裡簡單分為兩個過程,執行前和執行過程。你問的這個問題答案就出現在執行前階段。JavaScript是這樣的,在執行前時期,會把當前執行上下文的代碼全部掃描一遍,在這個時期生成一個變數對象VO,當所在執行上下文是函數內部時,這個VO會變成激活對象AO。這個VO/AO包括什麼內容呢?

VO/AO包括:變數聲明,函數聲明,以及函數形參。

先不講你那個例子,看下面這段代碼:

```

function test(a, b) {

var c = 10;

function d() {}

var e = function _e() {};

(function x() {});

}

test(10); // call

```

對於上面這段代碼,進入當前執行上下文生成的變數對象內容是(抽象表示):

AO(test) = {

a: 10,

b: undefined,

c: undefined,

d: &

e: undefined

};

所以你看到,在執行前階段,會把我上面說的那三種形式的內容添加到VO/AO中,這一切都發生在執行前。所以,這裡提一句,那所謂的變數聲明提升的原理也是因為這個。

當進入執行階段,每執行一句話,就會去更新這個VO/AO對象。而訪問某個標識符的時候,也是去VO/AO裡面去查找值的。所以,所謂的作用域鏈就是VO/AO的鏈

比如遇到這句話

var c = 10,更新VO/AO對象

VO["c"] = 10;

再回到你的這個例子,對於你這個例子生成的VO/AO如下:

VO ={

x:&

}

為什麼只有函數聲明x呢,這是因為根據規範定義,當執行上下文中具有同名的變數聲明和函數聲明的時候,變數聲明的優先順序是低於函數聲明的,所以函數聲明覆蓋變數聲明。所以,你訪問x時,實際上是存當前執行上文中的VO/AO對象裡面取得,這時候VO/AO對象中x的值就是函數x。


可以了解一下變數提升和函數提升

以function開頭的函數會觸發函數提升,以var聲明的變數會觸發變數提升。

所以

function a () {}

等同於

var a

a = function () {}

所以代碼中的var a無論放在function a的前還是後,最後在運行時都會先被賦值為function a的方法對象。然後再執行alert(a)

So...


JS不於其他解釋型語言,有編譯的階段,類似其他語言的JIT,存在變數和函數提升

具體細節可以參考《你不知道的JS(上)》


推薦閱讀:

原生js 有沒有 手機移動端 滑動 的事件?
原生 JS 代碼和用 jQuery 實現效果各有什麼優劣勢?

TAG:JavaScript | 前端工程師 | 原生JavaScript | JS調試 |