更新下相關知識,立足過往,擁抱將來。javascript
直接看規範關於ExecutionContext
的定義:java
An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation.
ExecutionContext
爲抽象概念,用來描述可執行代碼的執行環境。可執行代碼的運行,都是在ExecutionContext
中。git
ExecutionContextStack
Execution context Stack
爲後進先出(LIFO)的棧結構。棧頂永遠是running execution context
。當控制從當前execution context
對應可執行代碼轉移到另外一段可執行代碼時,相應的execution context
將被建立,並壓入棧頂,執行結束,對應的execution context
從棧頂彈出。github
ECMAScript
特性會使Execution context stack
不遵循LIFO
規則?規範裏面提到:ide
Transition of the running execution context status among execution contexts usually occurs in stack-like last-in/first-out manner. However, some ECMAScript features require non-LIFO transitions of the running execution context.
而後在規範裏面,並無找到some ECMAScript features
究竟是什麼特性。不過,第一反應,Generator
算不算?在stackoverflow上,有這麼一個討論Execution Context Stack. Violation of the LIFO order using Generator Function函數
function *gen() { yield 1; return 2; } let g = gen(); console.log(g.next().value); console.log(g.next().value);
調用一個函數時,當前execution context
暫停執行,被調用函數的execution context
建立並壓入棧頂,當函數返回時,函數execution context
被銷燬,暫停的execution context
得以恢復執行。post
如今,使用的是Generator
,Generator
函數的execution context
在返回yield
表達式的值以後仍然存在,並未銷燬,只是暫停並移交出了控制權,可能在某些時候恢復執行。學習
到底是不是呢?有待求證。ui
Lexical Environments
看規範的定義:this
A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code.
按規範來講,Lexical Environment
定義了標識identifiers
與Variables
或Functions
的映射。
Lexical Environment
包含兩部分:Environment Record
identifiers
與Variables
或Functions
的映射類型 | 簡述 |
---|---|
Declarative Environment Records | 記錄 var 、const 、let 、class 、import 、function 等聲明 |
Object Environment Records | 與某對象綁定,記錄該對象中string identifier 的屬性,非string identifier 的屬性不會被記錄。Object environment records 爲with 語句所建立 |
Function Environment Records | Declarative Environment Records 的一種,用於函數的頂層,若是爲非箭頭函數的狀況,提供this 的綁定,若還引用了 super 則提供super 方法的綁定 |
Global Environment Records | 包含全部頂層聲明及global object 的屬性,Declarative Environment Records 與Object Environment Records 的組合 |
Module Environment Records | Declarative Environment Records 的一種,用於ES module 的頂層,除去常量和變量的聲明,還包含不可變的import 的綁定,該綁定提供了到另外一environment records 的間接訪問 |
Lexical Environment
的引用null
Lexical Environment
分三類:Global Environment
Lexical Environment
的Lexical Environment
Module Environment
Lexical Environment
爲Global Environment
Function Environment
JavaScript
中的函數,其會創建this
的綁定以及必要的super
方法的綁定Variable Environments
在ES6前,聲明變量都是經過var
聲明的,在ES6後有了let
和const
進行聲明變量,爲了兼容var
,便用Variable Environments
來存儲var
聲明的變量。
Variable Environments
實質上仍爲Lexical Environments
具體能夠參考規範ECMAScript 2019 Language Specification。相關的是在8.3 Execution Contexts
。
一篇很不錯的文章參考Understanding Execution Context and Execution Stack in Javascript
, 該文章的中文翻譯版中文版
參考裏面的例子:
var a = 20; var b = 40; let c = 60; function foo(d, e) { var f = 80; return d + e + f; } c = foo(a, b);
建立的Execution Context
像這樣:
GlobalExecutionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Object", c: < uninitialized >, foo: < func > } outer: <null>, ThisBinding: <Global Object> }, VariableEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here a: undefined, b: undefined, } outer: <null>, ThisBinding: <Global Object> } }
在運行階段,變量賦值已經完成。所以GlobalExecutionContext
在執行階段看起來就像是這樣的:
GlobalExecutionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Object", c: 60, foo: < func >, } outer: <null>, ThisBinding: <Global Object> }, VariableEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here a: 20, b: 40, } outer: <null>, ThisBinding: <Global Object> } }
當遇到函數foo(a, b)
的調用時,新的FunctionExecutionContext
被建立並執行函數中的代碼。在建立階段像這樣:
FunctionExecutionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", Arguments: {0: 20, 1: 40, length: 2}, }, outer: <GlobalLexicalEnvironment>, ThisBinding: <Global Object or undefined>, }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", f: undefined }, outer: <GlobalLexicalEnvironment>, ThisBinding: <Global Object or undefined>, } }
執行完後,看起來像這樣:
FunctionExecutionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", Arguments: {0: 20, 1: 40, length: 2}, }, outer: <GlobalLexicalEnvironment>, ThisBinding: <Global Object or undefined>, }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", f: 80 }, outer: <GlobalLexicalEnvironment>, ThisBinding: <Global Object or undefined>, } }
在函數執行完成之後,返回值會被存儲在c
裏。所以GlobalExecutionContext
更新。在這以後,代碼執行完成,程序運行終止。
ECMAScript
規範是年年都在更新,得與時俱進的增強學習,立足過往及當下,擁抱將來!