1.變量聲明 提高:函數
console.log(typeof a); // undefined
var a = 1; console.log(typeof a); // number
執行過程 至關於:spa
var a; console.log(typeof a); // undefined
a = 1; console.log(typeof a); // number
2.函數聲明 提高:code
函數聲明 的提高是一個 總體提高的過程;blog
demo:開發
console.log(typeof a); // function
function a(){} console.log(typeof a); // function
如上的demo,足能夠證實,這一結論;假如不是總體提高,是相似於 var變量聲明的提高的方式,應該會如 var變量聲明的方式的輸出方式相同, 先輸出 undefined,再輸出 function;io
3.無所謂 函數聲明優先 or 變量聲明優先console
那麼,又來了個問題,既然 var聲明 和 函數聲明 都有提高機制,那麼它倆的聲明提高優先級是什麼樣子呢;編譯
爲了論證這個我在網上看了好多資料,也查了好多書籍,你們一直認爲 函數聲明提高 優先於 變量聲明提高,可是我發現,你們的論據都不夠充分;好比以下的一個論證:function
a(); // 1
var a; function a() { console.log(1); } a = function() { console.log(2); } a(); // 2
而後,也描述了它的執行過程,至關於:class
解釋 A:
function a(){ console.log(1); } var a; // 遇到沒有賦值的同名聲明,忽略,不作操做;至關於什麼都沒有作
a(); // 1
a = function(){ console.log(2); } a(); // 2
若是如上的操做的解釋,也能夠經過,能夠論證出 「函數聲明提高 優先於 變量聲明提高」;可是,按以下的理解應該也是解釋的通的啊:
解釋 B:
// 注意 var a 和 function a聲明都會在棧空間開闢存儲空間,而且 是佔用同一塊name爲 a的空間;
var a; // 此時 a 沒有賦值, 是個空的棧空間值
function a(){ // 找到 name爲a的棧空間,給它賦值 function(){console.log(1)}, 至關於覆蓋
console.log(1); } a(); // 1
a = function(){ console.log(2); } a(); // 2
看到了吧,如上的 論述也是行的通的,可是論述出來的結果 是「變量聲明提高 優先於 函數聲明提高」;這就尷尬了。。。
其實呢,我仔細想了一下,其實 誰先聲明提高的都無所謂,由於 「var a 和 function a聲明都會在棧空間開闢存儲空間,而且開闢的是同一塊 name爲 a的空間,也就是說它們用的是同一塊空間」;
4.函數聲明先賦值,變量聲明執行到賦值語句才賦值
由於兩種聲明方式共同操做一塊棧空間,因此,主要看是誰先賦值的,咱們再看一個例子:
console.log(typeof a); // function
var a = 1; function a(){} console.log(typeof a); // number
這就看的出來了,經過上邊的這個demo, 明顯能夠看出來,應該 函數聲明先賦值的,它是在執行上下文的執行階段一開始的時候就已經進行了賦值操做,因此 最開始 typeof a 能夠獲得 function;而,變量聲明 是要執行到賦值語句的時候才進行的賦值,因此 最後 typeof a 獲得是 number;
若是不是這樣的話,咱們不妨作下假設:
假設1:都是最先賦值,無論誰先賦值,結果以下:
/* ->var 聲明; ->函數聲明; ->var 賦值; ->函數賦值: ->console.log(typeof a); // function 或者 number ->console.log(typeof a); // function 或者 number */
結果如上,最後輸出不是同是 function 就是同是 number, 不符合正確輸出;
假設2:都是執行到賦值語句的時候才賦值,不管 兩種聲明 誰前誰後,結果以下:
/* ->var 聲明; ->函數聲明; ->console.log(typeof a); // undefined ->賦值操做: ->console.log(typeof a); // function 或者 number */
結果如上,第一個輸出必定都是 undefined, 不符合正確輸出;
假設3:經過 (1) 和 (2)的不經過,那麼只剩下一種可能了,都是先聲明,而後一個先賦值,一個到 執行語句的時候才賦值;也就推測出了咱們的結論:"函數聲明先賦值,變量聲明直到賦值語句的時候才賦值";執行過程以下:
/* -> a 聲明;// 由於同用一個棧空間,因此無所謂誰先聲明 -> 函數聲明賦值 ->console.log(typeof a); // function ->變量聲明賦值: ->console.log(typeof a); // number */
符合正確輸出的結果;因此結論成立;
其實 函數的總體提高方式就已經論證了這一點,不管是如 解釋 A 函數提高優先 + 忽略未賦值的 var 聲明, 仍是如 解釋 B變量聲明提高優先 + 函數後聲明覆蓋var 聲明,最後都是在同一個棧空間上進行的操做,並沒有所謂,重要的是誰先進行的賦值操做;還有就是如上的這種 變量聲明和函數聲明是同名的用法,儘可能不要在正式開發中使用,很容易就出現難以排查的異常;
4.總結
*->1.函數聲明 和 變量聲明都有聲明提高機制
*->2.函數聲明 是總體提高的方式,來進行的聲明提高;
*->3.函數聲明 和 變量聲明,無所謂誰優先於誰,都是在預編譯階段進行的;(根據第4點的總結,也能夠理解爲 函數聲明優先於變量聲明)
*->4.函數聲明賦值 要早於 函數聲明賦值
**->.函數聲明賦值,是在執行上下文的開始階段進行的;
**->.變量聲明賦值,是在執行到賦值語句的時候進行的賦值;
原創:轉載註明出處,謝謝 :)