Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重学js —— Lexical Environments(词法环境)和 Environment Records(环境记录) #49

Open
lizhongzhen11 opened this issue Oct 22, 2019 · 0 comments
Labels
重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Oct 22, 2019

Executable Code and Execution Contexts

Lexical Environments(词法环境)

Lexical Environments是一种规范类型,用于根据ECMAScript代码的词法嵌套结构定义标识符与特定变量和函数的关联。一个词法环境由一个Environment Records和一个可能为空的外部词法环境的引用组成。通常,词法环境与ECMAScript代码的特定句法结构有关。例如函数申明块语句try语句中的catch等代码每次运算后会产生新的词法环境。

一条Environment Records记录在其关联词法环境作用域内创建的标识符绑定。它指向词法环境的EnvironmentRecord

PS:便于理解,可以把词法环境间的嵌套看成 树结构

外部环境引用用于模拟词法环境值的逻辑嵌套。内部词法环境的外部引用 是对一个逻辑上围绕内部词法环境的词法环境的引用(有点绕人)。外部词法环境也会有它自己的外部词法环境(就像树形结构一样,子父级关系)。一个词法环境可以作为多个内部词法环境的外部环境(类似有多个子级)。

全局环境 是一个没有外部词法环境的词法环境(看作树的根节点)。全局环境的外部环境引用是 null。全局环境的EnvironmentRecord可能预填充了标识符绑定,并包括一个关联的全局对象,该对象的属性提供了某些全局环境的标识符绑定。当ECMAScript代码执行时,可能会对全局对象增加额外的属性并且初始属性可能会被修改。

module 环境是一个包含了模块顶级申明绑定的词法环境。 它还包含模块显式引入的绑定。module 环境的外部环境是全局环境。

function环境是一个对应于ECMAScript函数对象调用的词法环境。函数环境可能建立一个新的 this绑定。函数环境还捕获支持 super 方法调用所需的状态。

Lexical Environments 和 Environment Record 的值是纯规范机制并且不需要与任何特定的ECMAScript实现对应。ECMAScript程序是无法直接获取或操作它们的值的。

Environment Records

规范中有两种主要的Environment Records值:declarative Environment Recordsobject Environment Records

声明性环境记录用于定义ECMAScript语言语法元素(例如FunctionDeclarationsVariableDeclarationsCatch)的效果,这些元素直接将标识符绑定与ECMAScript语言值相关联

对象环境记录用于定义ECMAScript元素(例如WithStatement)的效果,这些元素将标识符绑定与某些对象的属性相关联。

全局环境记录和函数环境记录专门用于脚本全局声明和函数内顶级声明。

出于规范目的,环境记录值是Record规范类型的值并且可以认为它存在于简单的面向对象的层次结构中,其中Environment Record是具有三个具体子类的抽象类,分别是declarative Environment Record, object Environment Record, 和 global Environment Record。

Function Environment Records 和 module Environment Records是declarative Environment Record子类。这些抽象类包含一些抽象的方法定义在下面表格中:

方法 目标
HasBinding(N) 确定环境记录是否具有字符串值N的绑定。有的话返回true,否则返回false。
CreateMutableBinding(N, D) 在环境记录中创建一个新的但是未初始化且可变的绑定。字符串值N是绑定名称。如果布尔参数D是 true,那么这个绑定随后可能被删除。
CreateImmutableBinding(N, S) 在环境记录中创建一个新的但是未初始化且可变的绑定。字符串值N是绑定名称。如果S是 true,对其进行初始化之后进行设置,无论引用该绑定的操作的严格模式设置如何,都将始终引发异常。
InitializeBinding(N, V) 在环境记录中对一个已存在但未初始化的绑定设置值。字符串值N是绑定名称。V是绑定的值并且该值符合ECMAScript语言类型。
SetMutableBinding(N, V, S) 在环境记录中对一个已存在且可变的绑定设置值。字符串值N是绑定名称。V是绑定的值并且该值可能符合ECMAScript语言类型。S是一个布尔标志。如果S是true并且不能设置绑定则抛出一个类型错误。
GetBindingValue(N, S) 从环境记录中返回一个已存在绑定的值。字符串值N是绑定名称。S用于标识源自严格模式代码或其他需要严格模式引用语义的引用。如果S是true并且绑定不存在,抛出一个引用错误。如果绑定存在但未初始化,则无论S的值如何,都会引发ReferenceError。
DeleteBinding(N) 从环境记录中删除绑定。字符串值N是绑定名称。如果N的绑定存在,移除绑定并返回 true。如果绑定存在但不能被移除,返回 false。如果绑定不存在则返回 true
HasThisBinding() 取决于环境记录是否建立一个 this 绑定。如果有返回 true 否则返回 false
HasSuperBinding() 取决于环境记录是否建立一个 super 绑定。如果有返回 true 否则返回 false
WithBaseObject() 如果环境记录关联了一个 with 语句,返回 with 对象。否则,返回undefined

声明性环境记录(Declarative Environment Records)

每个声明性环境记录都与包含变量(var),常量(const),let,类(class),模块(module),导入(import)和函数声明(function)的ECMAScript程序作用域相关联。声明性环境记录绑定在其作用域内声明的标识符集。

SetMutableBinding ( N, V, S )方法,在某些很罕见的情况下没有存在的绑定,例如:

function f() { eval("var x; x = (delete x, 0);"); }

对象环境记录(Object Environment Records)

每个对象环境记录与其绑定对象相关联。对象环境记录绑定 直接与其绑定对象的属性名称 相对应的一组字符串标识符名称。不是以IdentifierName形式出现的字符串的属性键不包含在绑定标识符集中。自有以及继承的属性都会被包含在该集合内,无论它们的[[Enumerable]]属性设置。由于对象属性可以动态增加和删除,对象环境记录所绑定的标识符集可能会因添加或删除属性的任何操作的副作用而发生更改。由于这种副作用而创建的任何绑定都被视为可变绑定,即使相应属性的Writable属性的值为 false 也不例外。对象环境记录中不存在不可变绑定。

with 语句创建的对象环境记录可以提供它们的绑定对象作为一个隐式 this 值在函数调用中使用。该功能由与每个对象环境记录关联的withEnvironment布尔值控制。 默认情况下,对于任何对象环境记录,withEnvironment的值为false

Global Environment Records

全局环境记录用于表示在共同领域中处理的所有ECMAScript脚本元素共享的最外部作用域。全局环境记录为内置全局变量,全局对象的属性以及脚本中发生的所有顶级声明(13.2.813.2.10)提供了绑定。

逻辑上来说,全局环境记录是单个记录,但是它被指定为封装对象环境记录和声明性环境记录的 复合记录。对象环境记录将关联领域记录的全局对象作为其基对象。此全局对象是全局环境记录的GetThisBinding方法返回的值。全局环境记录的对象环境记录包含所有内置全局变量的绑定(第18节)以及全局代码中包含的FunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclarationVariableStatement引入的所有绑定。全局代码中所有其他ECMAScript声明的绑定包含在全局环境记录的声明性环境记录部分中。

可以直接在全局对象上创建属性。因此,全局环境记录的对象环境记录组件可能包含由FunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclarationVariableStatement声明显式创建的绑定,以及隐式创建为全局对象属性的绑定。为了识别使用声明显式创建的绑定,全局环境记录使用其CreateGlobalVarBinding和CreateGlobalFunctionBinding具体方法维护绑定名称的列表。

全局环境记录有额外的字段列表:

字段名 含义
[[ObjectRecord]] 对象环境记录 绑定的是全局对象。它在相关领域的全局代码中包含全局内置绑定以及FunctionDeclaration,GeneratorDeclaration,AsyncFunctionDeclaration,AsyncGeneratorDeclaration和VariableDeclaration绑定。
[[GlobalThisValue]] Object 全局作用域内返回this。主机可以返回任何ECMAScript对象值。
[[DeclarativeRecord]] 声明性环境记录 包含相关领域代码的全局代码中所有声明的绑定,但FunctionDeclaration,GeneratorDeclaration, AsyncFunctionDeclaration, AsyncGeneratorDeclaration, 和 VariableDeclaration 除外。
[[VarNames]] 字符串列表 在关联领域的全局代码中,由FunctionDeclaration,GeneratorDeclaration,AsyncFunctionDeclaration,AsyncGeneratorDeclaration和VariableDeclaration声明绑定的字符串名称。

Function Environment Records

Function 环境记录是一个声明性环境记录,用于表示函数的顶级作用域并且如果该函数不是一个箭头函数,则会提供一个 this 绑定。如果该函数不是箭头函数且有 super 引用,它的function环境记录还包含用于从function内部执行 super 方法调用的状态。

下面是函数环境记录额外的字段列表:

字段名 含义
[[ThisValue]] any 该函数调用时的 this
[[ThisBindingStatus]] lexical 或 initialized 或 uninitialized 如果值为lexical,则是箭头函数,没有this
[[FunctionObject]] Object 调用导致创建此环境记录的函数对象
[[HomeObject]] Object 或 undefined 如果关联的函数具有 super 属性访问权限,并且不是箭头函数,那么[[HomeObject]]是函数作为方法绑定到的对象。默认值是undefined
[[NewTarget]] Object 或 undefined 如果环境记录由[[Construct]]内置方法创建,则[[NewTarget]]是[[Construct]]参数newTarget的值。否则,它的值为undefined

Module Environment Records

module 环境记录是一个声明性环境记录,用于表示ECMAScript Module的外部作用域。此外,对于通常可变以及不可变的绑定,module 环境记录也会提供不可变的导入绑定(提供对另一个环境记录中存在的目标绑定的间接访问的绑定)。

词法环境是不是平常理解的作用域???

不全是。说环境记录是作用域可能更准确。
词法环境更像是作用域链。

2020-07-27 补充

来自高级前端面试小程序js基础第9题

var a = 10;
(function() {
  console.log(a); // undefined
  a = 5;
  console.log(window.a); // 10
  var a = 20;
  console.log(a); // 20
})()
@lizhongzhen11 lizhongzhen11 added the js基础 Good for newcomers label Oct 22, 2019
@lizhongzhen11 lizhongzhen11 changed the title 重学js —— 可执行代码和执行上下文 重学js —— Lexical Environments(词法环境)和 Environment Records(环境记录) Oct 22, 2019
@lizhongzhen11 lizhongzhen11 added the 重学js 重学js系列 规范+MDN label Jan 6, 2020
This was referenced Jan 9, 2020
@lizhongzhen11 lizhongzhen11 removed the js基础 Good for newcomers label Jan 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant