還原真實,javascript之預編譯 / 預解析

今天在羣裏吹水時,有羣友提出一個問題。我一看很簡單,就立馬給出了答案:由於存在變量提高,因此輸出undefined。本覺得無人反駁,可確招來口誅筆伐。做爲寫實派的我,一向以來堅持真實是個人使命,豈能容忍這等虛頭巴腦的言論攻擊。遂以此文記之,本在還原真實。奈何文筆拙劣,恐表述不當,誤人子弟。如有不當之處,還請衆佬及時斧正,以正視聽。javascript


就是下面這段代碼:java

var obj = {
  say: function () {
      
      console.log(obj)

  }()
}

// 輸出 undefined

爲何是undefined?node

這個問題看似簡單,不值一提,可其實是小孩沒娘,說來話長!編程

儘管如此,我仍是長話短說。很簡單,由於在javascript執行以前,是存在一個「預編譯」或者說是「預解析」這樣的過程,在這個過程中,進行了變量提高。瀏覽器

什麼是變量提高?
變量提高就是將變量名提高到其所在做用域的頂部並賦值爲undefined。與之相關的還有函數提高,不一樣的是,函數提高是將函數名及函數體所有提高到其所在做用域的頂部編程語言

與其說「預編譯」,「預解析」可能更合理一點。爲何這樣說?
由於在編程語言(如java,C#)當中,代碼都是要先編譯,後執行。而javascript做爲腳本語言,不一樣於編程語言的一點是沒有編譯過程,可是它須要腳本解釋器邊解析邊執行,而腳本解釋器在解釋執行代碼前會先掃描一遍,這個過程就是「預解析」過程。函數

那麼爲何會存在變量提高和函數提高呢?
在ES5當中,沒有塊級做用域的概念,只有全局做用域和函數做用域。聲明變量能夠用var關鍵字,也能夠直接聲明,只不過直接聲明的變量是全局變量,而用var關鍵字聲明的變量在全局做用域下就是全局變量,在函數體內就是局部變量。而且var關鍵字聲明的變量在其所在的做用域下存在變量提高。code

em... 那變量提高跟上面的代碼輸出的結果是undefined有什麼關係呢? 好,請坐下,陳獨秀同窗。對象

咱們來用代碼還原一下真實過程:ip

預解析階段:
生成全局對象,瀏覽器當中是window對象,node環境下是global對象
變量提高:
全局做用域下,變量obj提高到頂部,直接掛在window對象下,至關於window.obj = undefined;
say方法是一個匿名函數。匿名函數的函數體賦值給了變量say。因此變量say也會進行變量提高,它所在的做用域也是全局window下,至關於window.say = undefined;

函數提高:

function(){ 
  console.log(obj);  //obj = window.obj = undefined
}

執行階段:
1,建立一個執行上下文(execution context),函數壓棧,生成active object(活動對象)
1,執行/解釋上下文中的function,爲變量賦值
2,

參考:https://www.jianshu.com/p/edb2be5866eb

  • 須要記住的是:
    • 變量提高只提高變量名,函數提高會提高函數名及其函數體。
    • 變量提示優先級大於函數提高優先級。也就是說無論變量聲明在前仍是函數聲明在前,都是先進行變量提高,再進行函數提高。

執行階段:

function(){
  console.log(obj); //輸出undefined
}()
相關文章
相關標籤/搜索