JavaScript的代碼運行機制


這是一張簡單的JavaScript運行圖(若有錯誤地方請指出,謝謝你們)。大體分爲兩個階段,編譯階段和執行階段。在上一篇文章【JavaScript變量提高運行機制】中有簡單提到過。這篇文章帶你們來了解其中的一些概念。javascript

1、編譯階段

分詞/詞法分析

這個過程是將由字符組成的字符串分解爲有意義的代碼塊,這些代碼塊咱們稱之爲詞法單元(token)。例如:var num = 1;在當前階段會被分解爲var、num、=、一、空格,每個都是一個詞法單元,固然空格是不是一個有效的詞法單元取決於空格是否在JavaScript是否有意義。css

解析/語法分析

這個過程主要是將詞法單元流(數組)轉換爲一個由元素嵌套的程序語法樹(抽象語法樹,AST)。html

預解釋/代碼生成

這個階段主要是將AST轉換爲可執行代碼。這個階段會進行變量的提高java

引入幾個簡單的概念:數組

引擎:負責整個JavaScript的編譯和執行過程。編譯器:負責JavaScript的語法分析和代碼生成。做用域:負責收集並維護全部申明的標識符組成的一系列查詢,並實施一套規則,肯定當前執行的代碼對這些標識符的訪問權限。複製代碼

2、執行階段

一、可執行代碼

JavaScript並非簡單的一行行解釋執行,而是將JavaScript代碼分爲一塊塊的可執行代碼塊進行執行,JavaScript中主要主要分爲三類可執行代碼。
瀏覽器

  • 全局可執行代碼
  • 函數可執行代碼
  • Eval可執行代碼

二、JavaScript引擎


上圖描述了JavaScript的執行過程,具體過程咱們先不看。一個JS引擎主要有一下幾部分組成。bash

  • 編譯器:負責JavaScript的語法分析和代碼生成。
  • 解析器:在某些引擎中,解釋器主要是接收字節碼,解釋執行這個字節碼,同時也依賴垃圾回收機制等。
  • JIT:將字碼節或者抽象語法樹轉換爲本地可執行代碼。
  • 垃圾回收,分析工具:負責垃圾回收和收集引擎中的信息,幫助改善引擎的性能和功效。

三、JavaScript引擎的內存堆(emory Heap)和調用棧(Call Stack)

內存堆(emory Heap):分配內存地址
app

調用棧(Call Stack):代碼執行ide

let name = '蝸牛';

    function sayName(name) {
        sayNameStart(name);
    }
    function sayNameStart(name) {
        sayNameEnd(name);
    }
    function sayNameEnd(name) {
        console.log(name);
    }複製代碼

當代碼進行聲明時函數


執行sayName函數時,會把直接函數壓如執行棧,而且會建立執行上下文



四、執行上下文

JavaScript中每個可執行代碼,在解釋執行前,都會建立一個可執行上下文。按照可執行代碼塊可分爲三種可執行上下文

  • 全局可執行上下文:每個程序都有一個全局可執行代碼,而且只有一個。任何不在函數內部的代碼都在全局執行上下文。
  • 函數可執行上下文:每當一個函數被調用時, 都會爲該函數建立一個新的上下文。每一個函數都被調用時都會建立它本身的執行上下文。
  • Eval可執行上下文:Eval也有本身執行上下文。


五、執行上下文的建立

  • this的指向:除開箭頭函數的this是編輯階段肯定的以外,其餘this都是在代碼執行階段【代碼執行階段 == 執行上下文建立階段】確認的。

一、普通函數的調用:this指向window(瀏覽器環境)
二、對象方法的調用:this指向調用對象
三、構造函數:this指向構造函數實例
四、applycallbindthis指向綁定值
五、箭頭函數thisthis指向外層第一個普通函數調用的this複製代碼

  • 建立詞法環境
  1. 全局環境:全局環境的外部環境引用是 null,它擁有內建的 Object/Array/等、在環境記錄器內的原型函數(關聯全局對象,好比 window 對象)還有任何用戶定義的全局變量,而且 this的值指向全局對象。
  2. 模塊環境:包含模塊頂級聲明的綁定以及模塊顯式導入的綁定。 模塊環境的外部環境是全局環境。
  3. 函數環境:函數內部用戶定義的變量存儲在環境記錄器中,外部引用既能夠是其它函數的內部詞法環境,也能夠是全局詞法環境

詞法環境自己包括兩個部分:

  1. 『環境記錄器(Environment Record)』是存儲變量和函數聲明的實際位置
  2. 『外部環境的引用(outer Lexical Environment)』指它能夠訪問其父級詞法環境(即做用域)

對於『環境記錄器』而言,它又分爲兩個主要的環境記錄器類型:

  1. 聲明式環境記錄器(DecarativeEnvironmentRecord):範圍包含函數定義,變量聲明,try...catch等,此類型對應其範圍內包含的聲明定義的標識符集
  2. 對象式環境記錄器(ObjectEnvironmentRecord):由程序級別的(Program)對象、聲明、with語句等建立,與稱爲其綁定對象的對象相關聯,此類型對應於其綁定對象的屬性名稱的字符串標識符名稱集
  • 建立變量環境:變量環境也是一個詞法環境,但不一樣的是詞法環境被用來存儲函數聲明和變量(let 和 const)綁定,而變量環境只用來存儲 var 變量綁定。


六、代碼執行

當瀏覽器加載某些JavaScript代碼時,引擎會逐行讀取並執行如下步驟:

  • 使用變量和函數聲明填充全局內存(堆)
  • 將每一個函數調用推送到調用堆棧
  • 建立全局執行上下文,其中執行全局函數
  • 建立許多微小的本地執行上下文(若是有內部變量或嵌套函數)


3、小結

經過這個文章咱們能夠簡單的瞭解相關的JavaScript代碼執行機制。

參考:JavaScript的運行機制

                           

相關文章
相關標籤/搜索