JS預編譯

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

先來看這個題會alert出什麼呢?答案很顯然會是:1javascript

不過這道題目放在之前考個人話,那我必定會答錯,後來查找了一番資料,瞭解到兩個新名詞:預編譯變量提高,爲了之後不會忘記,仍是留個筆記吧。java

首先來了解一下什麼是預編譯:對var關鍵字(值先設爲undefined,執行時纔給實際值)和函數定義式進行提早聲明,再接着順序執行代碼,函數定義式在預編譯時期就被解析,執行時期仍然用這個值,而不管是聲明的變量仍是聲明式函數,在執行的時候,能夠覆蓋預編譯時期的值。函數

下面咱們來解釋一下上面的題目爲何是1呢,首先上面的代碼等價於下面的代碼:code

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

由於js沒有塊級做用域,因此if裏面的也是全局的,因此在預編譯過程當中裏面的變量a會被提出來並被賦值爲undefined,而後在執行if語句時候此時a已經存在於window中了,只不過值暫時是undefined,因而就會去執行if裏面的代碼,因此結果爲1;ip

再來一題:作用域

var a = 1;
function a(x){}
alert(a);

等價於:
var a;
a = function(x){}
a = 1;
alert(a);

預編譯階段尋找代碼中的var(實際將var a=1拆分爲var a;a=1兩部分,第一部分置頂,第二部分掛在語法樹上)以及function兩個關鍵字並置頂,在此將a以及a()分別置頂,以後在執行階段再對a從語法樹進行賦值,最後a爲1。io

理解了上面的代碼,下面再看一個相似的題目:編譯

function a(x) {
    return x ;
}
var a;
alert(a);

等價於:
var a;
function a(x){
    return x;
}
alert(a);

這個題目跟上一個有點相似,可是卻又不一樣,緣由就是在這裏a並無被賦值,而只是聲明一個變量;在預編譯階段會將這種形式提早置頂,而後將function也置頂,可是function在a以後,因而預編譯後兩者順序徹底倒過來了,因此最後執行結果是function a(x){return x;}。function

若是顯式的給a賦值一個a=undefined;那麼結果就是undefined。由於此時牽扯到賦值了 賦值的話 就在執行階段去執行。class

Fn();  //執行結果:"執行了函數2",同名函數後者會覆蓋前者
     function Fn(){ //函數1
        alert("執行了函數1");
     }
 
     function Fn(){  //函數2
        alert("執行了函數2");
     }
Fn();  //執行結果:"執行了聲明式函數",在預編譯期聲明函數及被處理了,因此即便Fn()調用函數放在聲明函數前也能執行。
      function Fn(){ //聲明式函數
         alert("執行了聲明式函數");
      }
 
      var Fn = function(){  //賦值式函數
         alert("執行了賦值式函數");
      }

經過對比上面兩段代碼,咱們不難發現,聲明式函數與賦值式函數的區別在於:在JS的預編譯期,聲明式函數將會先被提取出來,而後才按順序執行js代碼,因此纔有這樣的結果。

相關文章
相關標籤/搜索