你真的理解變量提高嗎?

什麼是變量提高

變量提高基礎概念其實很好理解:變量提高即將變量聲明提高到它所在做用域的最開始的部分。 可是咱們真的遇到變量提高的題目時,卻反而容易遺忘。如:程序員

if (! "a" in window) {
    var a = 1;
}

alert(a);  //undefined
複製代碼

第一遍閱讀代碼的感受是這樣的:若是全局對象中不存在a這個屬性沒,那麼設置全局變量a=1。 那麼答案應該等於1纔對,爲何是undefined呢?
由於a被變量提高了!
再次解析上面代碼,其實至關於如下代碼:es6

/**
上面這段代碼至關於
**/
var a;
if (! "a" in window) {
    a = 1;
}
alert(a); 
複製代碼

首先,咱們須要知道一個概念:js運行時,會分兩步進行操做,先進行解析,再執行
面試

解析,也就是建立變量和聲明函數。js會將全部var定義的變量和function都提高到做用域的頂端。並檢查時候有語法錯誤。如:Uncaught ReferenceError等。segmentfault

執行,js從上向下開始運行代碼。
bash

這樣咱們就能夠清晰地看出a是undefined了。函數


爲何要有變量提高

參考自:segmentfault.com/q/101000001…工具

以前一直不理解爲何要有變量提高,這只是一個js設計的缺陷嗎?若是是缺陷爲何不一開始就解決掉他呢?(如今es6已經使用let代替var)他以前有沒有什麼存在的意義呢?性能

提升性能

解析的過程當中,還會爲函數生成預編譯代碼。在預編譯時,會統計該函數聲明瞭哪些變量、建立了哪些函數(注:這裏就是聲明提高),並對函數的代碼進行壓縮,去除註釋、沒必要要的空白等。這樣作的好處是每次執行函數時均可以直接爲該函數分配棧空間(不須要再解析一遍去獲取函數中聲明瞭哪些變量,注:這也是聲明提高的好處),而且代碼執行更快(由於壓縮而變短了)。兩個好處都會提升執行函數的性能。測試

容錯性更好

咱們知道,JS是一種腳本語言,在發佈以後很長時間內都沒有爲程序員提供編譯器、調試器、語法檢查器等工具。在很長一段時間內其地位始終是Web頁面的附屬品,僅僅用來給頁面添加一些非必要的動態效果,而且其開發和部署也具備很強的隨意性,未通過調試和測試的代碼比比皆是。
spa

簡而言之,之前的js並非很被人看好,只當他是個腳本語言,經過這個方法能夠簡化開發,減小報錯,增長容錯率。

函數提高的必要性

其實提高功能不可替代的狀況是用在函數提高上。如:

function func1() {
    func2();
}
fun1();
function func2() {
    alert('success');
}
複製代碼

這是咱們很常見的申明函數的狀況,若是沒有函數提高,在執行到fun2()時會直接報錯,由於此時func1還並未定義。


那麼咱們最後來討論一下,變量提高真的是設計缺陷嗎?
我認爲多是的。由於在如今的開發中,變量提高只會加大咱們對代碼的理解的難度。 有時候會形成咱們意想不到的問題,形成不是咱們想要的結果,(如上面的題目)並且很難排查。也正如大衆對JavaScript的評價就是:它的優秀之處並不是原創,它的原創之處並不優秀


常見面試題

9道面試題

參考自 www.jianshu.com/p/864b0003d…

寫出下列顯示的值

(function(){
    a = 5;
    alert(window.a);
    var a = 10;
    alert(a);
})();
複製代碼

解題過程:這是利用了當即執行函數來模擬塊級做用域的寫法。由於函數提高就是把變量聲明提高到它所在做用域的最開始的部分,因此上面代碼至關於:

(function(){
    var a;    //局部變量a,默認值是undefined
    a = 5;    //因和局部變量名相同,所以全局變量a被覆蓋,此處變成了給局部變量a賦值
    //alert(a);  彈出5
    //a只是變量,而不是屬性 alert(a in window)返回false  ,參見http://segmentfault.com/q/1010000002883076 的第一個回答
    alert(window.a);  
    a = 10;
    alert(a);
})();
複製代碼

因此答案是 undefined和10

相關文章
相關標籤/搜索