66
77## 答案
88
9- ` this ` 是 JavaScript 中 ` 执行环境 ` 里的一个属性。主要用途通常是在函数和构造函数中。使用规则很简单(如果你坚持最佳实践的话)。
9+ ` this ` 是 JavaScript 中 ` 执行环境 ` 里的一个属性。主要用途通常是在函数和构造函数中。
1010
1111### ECMA规范中对 this 的技术描述
1212
13- [ ECMAScript标准] ( https://tc39.es/ecma262/ ) 通过 [ ResolveThisBinding] ( https://tc39.es/ecma262/#sec-resolvethisbinding ) AO(一种抽象操作 ,缩写为AO) 来定义 [ this] ( https://tc39.es/ecma262/#sec-this-keyword ) :
13+ [ ECMAScript标准] ( https://tc39.es/ecma262/ ) 通过 [ ResolveThisBinding] ( https://tc39.es/ecma262/#sec-resolvethisbinding ) AO(可以理解成是一种抽象方法 ,缩写为AO) 来定义 [ this] ( https://tc39.es/ecma262/#sec-this-keyword ) :
1414
1515``` text
1616ResolveThisBinding 不需要任何参数。它使用运行中的执行环境的 [词法环境 LexicalEnvironment] 来完成 this 的绑定。在被调用时执行以下步骤。
@@ -21,17 +21,17 @@ ResolveThisBinding 不需要任何参数。它使用运行中的执行环境的
2121
2222[ 全局环境记录 Global Environment Records] ( https://tc39.es/ecma262/#sec-global-environment-records ) 、[ 模块环境记录 Module Environment Records] ( https://tc39.es/ecma262/#sec-module-environment-records ) 和 [ 函数环境记录 Function Environment Records] ( https://tc39.es/ecma262/#sec-function-environment-records ) 都有自己的 ` GetThisBinding ` 方法。
2323
24- 通过 ` GetThisEnvironment ` AO 找到当前执行环境中的 ` 词法环境 LexicalEnvironment ` ,并找到最接近的具有此绑定(即 ` HasThisBinding ` 返回 true )的环境记录(通过迭代访问其 ` [[OuterEnv]] ` 属性)。这个过程最后会产生上述 ` 三种环境记录类型 ` 中的一种 。
24+ 通过 ` GetThisEnvironment ` AO 找到当前执行环境中的 ` 词法环境 LexicalEnvironment ` ,并找到最接近的具有此绑定(即 ` HasThisBinding ` 返回 true )的环境记录(通过迭代访问其 ` [[OuterEnv]] ` 属性)。然后会产生上述 ` 三种环境类型 ` 中的一种环境记录 。
2525
26- ` this ` 往往取决于代码环境是否处于 ` 严格模式(strict mode) ` 中。
26+ ` this ` 往往也取决于代码环境是否处于 ` 严格模式(strict mode) ` 中。
2727
2828` GetThisBinding ` 的返回值就是当前执行上下文的 ` this ` ,所以每当建立一个新的执行上下文时,` this ` 就会解析为一个不同的值。当当前执行上下文被修改时也会发生这种情况。
2929
3030下面的例子列出了可能发生这种情况的五种场景:
3131
32- ### 1.脚本中的全局执行上下文
32+ ### 1. script 中的执行上下文
3333
34- 例如,这是在最顶层执行的代码,直接在` <script> ` 内。
34+ 例如,这是在最顶层执行的代码,直接在 ` <script> ` 内。
3535
3636``` html
3737<script >
@@ -44,23 +44,25 @@ setTimeout(function(){
4444 </script >
4545```
4646
47- 当脚本代码在全局环境中执行代码时 , ` GetThisBinding ` 将有以下步骤。
47+ 当脚本代码在全局环境中执行时 , ` GetThisBinding ` 的步骤如下:
4848
4949``` text
5050The GetThisBinding concrete method of a global Environment Record envRec […] [does this]:
5151
5252Return envRec.[[GlobalThisValue]].
5353```
5454
55- ` 全局环境记录 ` 的 ` [[GlobalThisValue]] ` 属性总是被设置为当前环境的全局对象,它可以通过 ` globalThis ` (Web 上的 ` window ` ,Node.js 上的 ` global ` ;[ MDN上的文档] ( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis ) )访问。你也可以按照 [ InitializeHostDefinedRealm] ( https://tc39.es/ecma262/#sec-initializehostdefinedrealm ) 的步骤来学习 ` [[GlobalThisValue]] ` 的属性是如何形成的。
55+ ` 全局环境记录 ` 的 ` [[GlobalThisValue]] ` 属性始终被设置为当前环境的全局对象,可以直接通过 ` globalThis ` (Web 上的 ` window ` ,Node.js 上的 ` global ` ;[ MDN上的文档] ( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis ) )进行访问,也就是指向全局变量。
56+
57+ 你可以访问 [ InitializeHostDefinedRealm] ( https://tc39.es/ecma262/#sec-initializehostdefinedrealm ) 进一步了解 ` [[GlobalThisValue]] ` 的属性是如何形成的。
5658
5759### 2. module 中的执行上下文
5860
59- module 在 ` ECMAScript 2015 ` 中被引入。
61+ ` module ` 在 ` ECMAScript 2015 ` 中被引入。
6062
6163例子:直接在 ` <script type="module"> ` 里面执行的代码。
6264
63- 当 module 在全局环境中执行代码时,` GetThisBinding ` 将有以下步骤。
65+ 当 ` module ` 在全局环境中执行代码时,` GetThisBinding ` 的步骤如下:
6466
6567``` text
6668The GetThisBinding concrete method of a module Environment Record […] [does this]:
@@ -70,18 +72,18 @@ Return undefined.
7072
7173因此在 ` module ` 中,` this ` 在全局范围内始终是 ` undefined ` 。` module ` 默认是开启严格模式的。
7274
73- ### 3. 进入 eval 上下文
75+ ### 3. eval 中的执行上下文
7476
75- ` eval ` 有两种调用方式 :[ 直接调用] ( https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation ) 和 [ 间接调用] ( https://tc39.es/ecma262/#sec-eval-x ) 。这种区别从 ` ECMAScript第五版 ` 就开始存在 。
77+ 从 ` ECMAScript 第五版 ` 的时候, ` eval ` 就有两种调用方式 :[ 直接调用] ( https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation ) 和 [ 间接调用] ( https://tc39.es/ecma262/#sec-eval-x ) 。
7678
7779- 直接调用的 ` eval ` 通常看起来像 ` eval(...); ` 或者 ` (eval)(...); ` ,只有在调用表达符合狭义模式的情况下才是 ` 直接 ` 的。
7880- 间接调用的 ` eval ` 通常是以调用函数引用 ` eval ` 来完成的,比如:` eval?.(…) ` , ` (…, eval)(…) ` , ` window.eval(…) ` , ` eval.call(…,…) ` 等...
7981
80- 通过 [ performeval] ( https://tc39.es/ecma262/#sec-performeval ) 执行 ` eval ` 代码时,会创建一个新的 [ 声明性环境记录] ( https://tc39.es/ecma262/#sec-declarative-environment-records ) 作为其 ` 词法环境 LexicalEnvironment ` ,这也是 ` GetThisEnvironment ` 获取 ` this ` 值的地方。
82+ 通过 [ performeval] ( https://tc39.es/ecma262/#sec-performeval ) AO 执行 ` eval ` 代码时,会创建一个新的 [ 声明性环境记录] ( https://tc39.es/ecma262/#sec-declarative-environment-records ) 作为其 ` 词法环境 LexicalEnvironment ` ,前边说过,这是通过 ` GetThisEnvironment ` AO 获取 ` this ` 值的地方。
8183
82- 如果 ` this ` 出现在 ` eval ` 代码中,将由 ` GetThisEnvironment ` 找到的环境记录的 ` GetThisBinding ` 方法,直接调用并返回其值 。
84+ 如果 ` this ` 出现在 ` eval ` 代码中,先通过 ` GetThisEnvironment ` AO 找到其环境记录,在直接调用 ` GetThisBinding ` AO 并返回其值 。
8385
84- 而刚刚所介绍的 ` 声明性环境记录 ` 来源哪里,是取决于 ` eval ` 的调用方式是 ` 直接 ` 还是 ` 间接 ` 。
86+ 刚刚所说的 ` 声明性环境记录 ` 来源哪里,是取决于 ` eval ` 的调用方式是 ` 直接 ` 还是 ` 间接 ` 。
8587
8688- 在 ` 直接 ` 调用中,它将基于当前运行的执行环境中的 ` 词法环境 LexicalEnvironment ` 。
8789- 在 ` 间接 ` 调用中,它将基于执行当前环境记录中的 ` [[GlobalEnv]] ` 属性(一个全局环境记录)。
@@ -93,7 +95,7 @@ Return undefined.
9395
9496那么 ` new Function ` 呢?- ` new Function ` 与 ` eval ` 类似,但它并不立即调用代码,而是创建一个构造函数。在构造函数中的任何地方都不适用 ` this ` 的绑定,但是当这个函数被调用时,` this ` 才能够发挥作用,下一小节会继续进行相关解释
9597
96- ### 4. 进入 function 执行上下文
98+ ### 4. function 中的执行上下文
9799
98100在调用一个函数时,我们将进入 function 执行上下文,目前有四种语法可以调用一个函数。
99101
0 commit comments