前言
企業(yè)建站必須是能夠以充分展現(xiàn)企業(yè)形象為主要目的,是企業(yè)文化與產(chǎn)品對外擴(kuò)展宣傳的重要窗口,一個合格的網(wǎng)站不僅僅能為公司帶來巨大的互聯(lián)網(wǎng)上的收集和信息發(fā)布平臺,成都創(chuàng)新互聯(lián)公司面向各種領(lǐng)域:成都衛(wèi)生間隔斷等成都網(wǎng)站設(shè)計、成都營銷網(wǎng)站建設(shè)解決方案、網(wǎng)站設(shè)計等建站排名服務(wù)。
作為一個前端開發(fā)人員,弄清楚JavaScript的執(zhí)行上下文有助于我們理解js中一些晦澀的概念,比如閉包,作用域,變量提升等等。
執(zhí)行棧
執(zhí)行棧用于存儲代碼執(zhí)行期間創(chuàng)建的所有執(zhí)行上下文。具有FILO接口,也被稱為調(diào)用棧。
當(dāng)JavaScript代碼被運(yùn)行的時候,會創(chuàng)建一個全局上下文,并push到當(dāng)前執(zhí)行棧。之后當(dāng)發(fā)生函數(shù)調(diào)用的時候,引擎會為函數(shù)創(chuàng)建一個函數(shù)執(zhí)行上下文并push到棧頂。引擎會先執(zhí)行調(diào)用棧頂部的函數(shù),當(dāng)函數(shù)執(zhí)行完成后,當(dāng)前函數(shù)的執(zhí)行上下文會被移除當(dāng)前執(zhí)行棧。并移動到下一個上下文。
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')
執(zhí)行上下文
我們可以理解為執(zhí)行上下文是js代碼被解析和執(zhí)行時所在環(huán)境的抽象概念。
JavaScript的執(zhí)行上下文分為三種類型:
執(zhí)行上下文的創(chuàng)建
創(chuàng)建執(zhí)行上下文又可以分為兩個階段: 1. 創(chuàng)建階段 2. 執(zhí)行階段
創(chuàng)建階段
在創(chuàng)建階段,JavaScript引擎會創(chuàng)建LexicalEnvironment(詞法環(huán)境)組件,VariableEnvironment(變量環(huán)境)組件以及this綁定(在全局上下文中,this指向全局對象。在函數(shù)執(zhí)行上下文中,this取決與函數(shù)在哪里被調(diào)用。)
Lexical Environment(詞法環(huán)境)
ES2015規(guī)范對詞法環(huán)境的描述
我們可以理解為詞法環(huán)境是一種包含標(biāo)識符(變量/函數(shù)的名稱)和變量(實(shí)際對象:函數(shù)/原始值/數(shù)組對象等)映射的數(shù)據(jù)結(jié)構(gòu)。
每個詞法環(huán)境由兩部分組成:Environment Record環(huán)境記錄(存儲變量和函數(shù)聲明的實(shí)際位置)和對外部環(huán)境的引用(可以訪問其外部詞法環(huán)境)
環(huán)境記錄分為兩種:
tips:對于函數(shù)執(zhí)行上下文來說,環(huán)境記錄還包含了一個arguments對象,包含了傳遞給函數(shù)的索引和參數(shù)之間的映射以及函數(shù)參數(shù)的數(shù)量。
例如:
function foo(a, b) { var c = a + b } // argument object Arguments: {0: 2, 1: 3, length: 2}
VariableEnvironment(變量環(huán)境)
變量環(huán)境也是一個詞匯環(huán)境,因此它具有上面定義的詞法環(huán)境的所有屬性和組件。在ES6中,LexicalEnvironment組件和VariableEnvironment組件之間的一個區(qū)別是前者用于存儲函數(shù)聲明和變量let和const綁定,而后者僅用于存儲變量var綁定。
執(zhí)行階段
在執(zhí)行階段,會完成對所有變量的分配,代碼也會被最終執(zhí)行。執(zhí)行上下文的代碼會被分成兩個階段:
let a = 20 const b = 30 var c function multiply(e, f) { var g = 20 return e * f * g } c = multiply(20, 30)
當(dāng)上面的代碼被執(zhí)行的時候,JavaScript引擎會創(chuàng)建一個全局上下文來執(zhí)行全局代碼。
此時的全局上下文:
GlobalExectionContext = { // 全局上下文 LexicalEnvironment: { // 詞法環(huán)境 EnvironmentRecord: { // 環(huán)境記錄 type: 'Object', // 類型 // 標(biāo)識符 a:, b: , multiply: }, outer: , // 對外部環(huán)境引用 }, VariableEnvironment: { // 變量環(huán)境 EnvironmentRecord: { // 環(huán)境記錄 type: 'Object', c: undefined }, outer: , // 對外部環(huán)境引用 }, ThisBinding: // this綁定 }
在執(zhí)行階段,變量會被賦值,此時的全局上下文變成:
GlobalExectionContext = { LexicalEnvironment: { EnvironmentRecord: { type: 'Object', a: 20, b: 30, multiply:}, outer: }, VariableEnvironment: { EnvironmentRecord: { type: 'Object', c: undefined } outer: }, ThisBinding: }
當(dāng)JavaScript引擎遇到函數(shù)multiply(20, 30)的時候,會創(chuàng)建一個新的函數(shù)上下文:
FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { type: 'Declarative', arguments: { 0: 20, 1: 30, length: 2 } }, outer:}, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", g: undefined }, outer: , }, thisBinding: }
之后執(zhí)行上下文會進(jìn)入執(zhí)行階段, 此時的函數(shù)上下文:
FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { type: 'Declarative', arguments: { 0: 20, 1: 30, length: 2 } }, outer:}, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", g: 20 }, outer: , }, thisBinding: }
當(dāng)函數(shù)執(zhí)行完畢后。會返回一個值并賦值給變量c,全局上下文被更新。更新完成后,代碼執(zhí)行完畢,程序結(jié)束。
參考文章
Understanding Execution Context and Execution Stack in Javascript
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對創(chuàng)新互聯(lián)的支持。