本文部分內容轉自https://www.cnblogs.com/CBDoctor/p/3745246.html
1.變量提升
1 console.log(global); // undefined 2 var global = 'global'; 3 console.log(global); // global 4 5 function fn () { 6 console.log(a); // undefined 7 var a = 'aaa'; 8 console.log(a); // aaa 9 } 10 fn();
疑問一:
還沒有定義a和global,為什么就變成了undefined呢?
2.函數提升
1 console.log(f1); // function f1() {} 2 console.log(f2); // undefined 3 function f1() {} 4 var f2 = function() {}
疑問二:
console.log(f1)為什么能夠輸出還未定義初始化的f1函數呢?
疑問三:
類似於疑問一,為什么f2還沒定義,就輸出undefined呢?
這些疑問的答案,都來自JS的預編譯機制:
3.預編譯
JS並不會完全按照代碼順序進行解析執行,而是在解析之前進行一次“預編譯”。在此過程中,會把:
(1)定義式的函數優先執行
(2)所有var變量定義,默認值為undefined
這就解釋了上面兩段代碼輸出的原因了,上面的兩段代碼我們可以用下面的形式理解:
變量提升:
1 var global; 2 console.log(global); // undefined 3 global = 'global'; 4 console.log(global); // global 5 6 function fn () { 7 var a; 8 console.log(a); // undefined 9 a = 'aaa'; 10 console.log(a); // aaa 11 } 12 fn();
函數提升:
1 function f1() {} 2 var f2; 3 console.log(f1); 4 console.log(f2); 5 f2 = function() {}
4.容易出錯的一點
1 // 調用函數,返回值1 2 f(); 3 function f(){ 4 alert(1); 5 } 6 7 // 調用函數,返回語法錯誤。 8 f(); 9 var f = function(){ 10 alert(1); 11 }
這個一看就懂為啥了,在預編譯階段,聲明了變量f,而沒有為它賦值(匿名函數)。直接調用,肯定出錯。
5.總結
JS加載包含預編譯和執行兩個階段。 編譯階段會對所有的var變量和function進行掃描,並將var變量初始化為undefined類型,而function則被初始化為函數值。
到了執行階段,JS從上面往下面依順序執行,遇到var變量便進行賦值(因此,在賦值之前進行調用的話會出現錯誤).遇到函數變量的話會從活動對象中尋找函數