前端基础 | 结合规范了解this
通过阅读大佬文章,结合es规范,重新学习下 this的问题
建议将上面文章结合规范一起阅读
接上一篇执行上下文
执行上下文分为两个阶段:
- 创建执行上下文
- 执行阶段
创建执行上下文又分为 3 步:
- 确定
this指向 - LexicalEnvironment(词法环境) 组件被创建
- VariableEnvironment(变量环境) 组件被创建
这里只说说 this
ECMAScript 的类型分为语言类型 和 规范类型。
我们常说的 Undefined, Null, Boolean, String, Number 和 Object 属于 语言类型。
规范类型 是 「只存在于规范里的抽象类型」。它们是为了更好地描述语言的底层行为逻辑才存在的,但并不存在于实际的 js 代码中。
规范类型包括:Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record。
其中 Reference 类型 和 this 的指向有密切联系。
Reference 有且仅有三个组成部分:
base value: 属性所在的对象或者就是EnvironmentRecord,值只可能是undefined,an Object,a Boolean,a String,a Number, oran environment record其中的一种。referenced name: 属性的名称。strict reference: 是否是严格模式
通过两个例子来记忆一下:
1 | var foo = 1; |
1 | var foo = { |
Reference 提供了两个方法:
- GetBase: 返回
reference的base value。**返回的是一个具体值,而不再是一个Reference**。 - IsPropertyReference:
base value 是一个对象,就返回true,否则返回 false
这里再引入一个新名词:MemberExpression
查阅ES规范:http://es5.github.io/#x11.2
MemberExpression 的值为:
- PrimaryExpression // 原始表达式
- FunctionExpression // 函数定义表达式
- MemberExpression [ Expression ] // 属性访问表达式
- MemberExpression . IdentifierName // 属性访问表达式
- new MemberExpression Arguments // 对象创建表达式
例如:
1 | function foo() { |
简单理解 MemberExpression 其实就是()左边的部分。
如何确定 this?
建议仔细理解前面的内容!
查阅 ES规范:http://es5.github.io/#x11.2.3,简单总结成2步:
- 计算
MemberExpression的结果赋值给ref - 判断
ref是不是一个Reference类型- 2.1 如果
ref 是 Reference,并且IsPropertyReference(ref) 是 true, 那么this 的值为 GetBase(ref)(由前面可知,GetBase(ref)即为base value) - 2.2 如果
ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)。查阅 es规范:http://es5.github.io/#x10.2.1.2.6可知,ImplicitThisValue(ref) 函数始终返回 undefined - 2.3 如果
ref 不是 Reference,那么this 的值为 undefined
- 2.1 如果
如何判断是不是 Reference 类型
建议在「英文版规范」中全局搜索关键词
Return a value of type Referen,然后阅读搜索结果所属部分的内容. 得出如下结论:
两种创建 Reference 的途径:
- 标识符解析
- 属性访问
比如,foo 和 foo.bar 创建了一个 Reference ,而字面量(1,“foo”,[1,3]等)或函数表达式——(function(){})却不会。有一张来自网络的图作了个概括:

例子:
1 | var value = 1; |
根据上述的两个步骤进行判断:
foo.bar()
MemberExpression的结果为foo.bar- 确定
foo.bar是不是Reference类型(前面介绍了如何判断,不清楚的往前翻一翻):- 2.1
foo.bar属于属性访问,所以它是 Reference 类型。
- 2.1
由前文得出:
1 | var Reference = { |
由前文,判断出 IsPropertyReference(ref) 值为 true,所以 this 值为 GetBase(ref),即为 base value,所以 this 值为 foo
例子:
1 | function foo() { |
分析:
1 | var reference = { |
EnvironmentRecord 不属于 Object,所以 IsPropertyReference(ref)为 false ,则 this 指向 ImplicitThisValue(ref),而前面说了,
所以 this 指向 undefined
注意:
如果你在浏览器执行上述代码,你会在控制台发现输出的是
window对象??
查阅规范http://es5.github.io/#x10.4.3
「Entering Function Code」,第二条显示。
if thisArg is
nullorundefined, set the ThisBinding to theglobal object.