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代碼,因此纔有這樣的結果。