您好,登錄后才能下訂單哦!
前言
作為一個前端開發人員,弄清楚JavaScript的執行上下文有助于我們理解js中一些晦澀的概念,比如閉包,作用域,變量提升等等。
執行棧
執行棧用于存儲代碼執行期間創建的所有執行上下文。具有FILO接口,也被稱為調用棧。
當JavaScript代碼被運行的時候,會創建一個全局上下文,并push到當前執行棧。之后當發生函數調用的時候,引擎會為函數創建一個函數執行上下文并push到棧頂。引擎會先執行調用棧頂部的函數,當函數執行完成后,當前函數的執行上下文會被移除當前執行棧。并移動到下一個上下文。
let a = 'Hello' function first() { console.log('Inside first function') second() console.log('Again inside first function') } function second() { console.log('Inside second function') } first() console.log('Inside Global execution context')
執行上下文
我們可以理解為執行上下文是js代碼被解析和執行時所在環境的抽象概念。
JavaScript的執行上下文分為三種類型:
執行上下文的創建
創建執行上下文又可以分為兩個階段: 1. 創建階段 2. 執行階段
創建階段
在創建階段,JavaScript引擎會創建LexicalEnvironment(詞法環境)組件,VariableEnvironment(變量環境)組件以及this綁定(在全局上下文中,this指向全局對象。在函數執行上下文中,this取決與函數在哪里被調用。)
Lexical Environment(詞法環境)
ES2015規范對詞法環境的描述
我們可以理解為詞法環境是一種包含標識符(變量/函數的名稱)和變量(實際對象:函數/原始值/數組對象等)映射的數據結構。
每個詞法環境由兩部分組成:Environment Record環境記錄(存儲變量和函數聲明的實際位置)和對外部環境的引用(可以訪問其外部詞法環境)
環境記錄分為兩種:
tips:對于函數執行上下文來說,環境記錄還包含了一個arguments對象,包含了傳遞給函數的索引和參數之間的映射以及函數參數的數量。
例如:
function foo(a, b) { var c = a + b } // argument object Arguments: {0: 2, 1: 3, length: 2}
VariableEnvironment(變量環境)
變量環境也是一個詞匯環境,因此它具有上面定義的詞法環境的所有屬性和組件。在ES6中,LexicalEnvironment組件和VariableEnvironment組件之間的一個區別是前者用于存儲函數聲明和變量let和const綁定,而后者僅用于存儲變量var綁定。
執行階段
在執行階段,會完成對所有變量的分配,代碼也會被最終執行。執行上下文的代碼會被分成兩個階段:
let a = 20 const b = 30 var c function multiply(e, f) { var g = 20 return e * f * g } c = multiply(20, 30)
當上面的代碼被執行的時候,JavaScript引擎會創建一個全局上下文來執行全局代碼。
此時的全局上下文:
GlobalExectionContext = { // 全局上下文 LexicalEnvironment: { // 詞法環境 EnvironmentRecord: { // 環境記錄 type: 'Object', // 類型 // 標識符 a: <uninitialized>, b: <uninitialized>, multiply: <func> }, outer: <null>, // 對外部環境引用 }, VariableEnvironment: { // 變量環境 EnvironmentRecord: { // 環境記錄 type: 'Object', c: undefined }, outer: <null>, // 對外部環境引用 }, ThisBinding: <Global Object> // this綁定 }
在執行階段,變量會被賦值,此時的全局上下文變成:
GlobalExectionContext = { LexicalEnvironment: { EnvironmentRecord: { type: 'Object', a: 20, b: 30, multiply: <func> }, outer: <null> }, VariableEnvironment: { EnvironmentRecord: { type: 'Object', c: undefined } outer: <null> }, ThisBinding: <Global Object> }
當JavaScript引擎遇到函數multiply(20, 30)的時候,會創建一個新的函數上下文:
FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { type: 'Declarative', arguments: { 0: 20, 1: 30, length: 2 } }, outer: <GlobalLexicalEnvironment> }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", g: undefined }, outer: <GlobalLexicalEnvironment>, }, thisBinding: <Global Object or undefined> }
之后執行上下文會進入執行階段, 此時的函數上下文:
FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { type: 'Declarative', arguments: { 0: 20, 1: 30, length: 2 } }, outer: <GlobalLexicalEnvironment> }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", g: 20 }, outer: <GlobalLexicalEnvironment>, }, thisBinding: <Global Object or undefined> }
當函數執行完畢后。會返回一個值并賦值給變量c,全局上下文被更新。更新完成后,代碼執行完畢,程序結束。
參考文章
Understanding Execution Context and Execution Stack in Javascript
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。