建议将上面文章结合规范一起阅读
接上一篇执行上下文
执行上下文分为两个阶段:
- 创建执行上下文
- 执行阶段
创建执行上下文又分为 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: 是否是严格模式
通过两个例子来记忆一下:
var foo = 1;
// 对应的Reference是:
var fooReference = {
base: EnvironmentRecord,
name: 'foo',
strict: false
};
var foo = {
bar: function () {
return this;
}
};
foo.bar(); // foo
// bar对应的Reference是:
var BarReference = {
base: foo,
propertyName: 'bar',
strict: false
};
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 // 对象创建表达式
例如:
function foo() {
console.log(this)
}
foo(); // MemberExpression 是 foo
function foo() {
return function() {
console.log(this)
}
}
foo()(); // MemberExpression 是 foo()
var foo = {
bar: function () {
return this;
}
}
foo.bar(); // MemberExpression 是 foo.bar
简单理解 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(){})却不会。有一张来自网络的图作了个概括:

例子:
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
//示例1
console.log(foo.bar());
根据上述的两个步骤进行判断:
foo.bar()
MemberExpression的结果为foo.bar- 确定
foo.bar是不是Reference类型(前面介绍了如何判断,不清楚的往前翻一翻):- 2.1
foo.bar属于属性访问,所以它是 Reference 类型。
- 2.1
由前文得出:
var Reference = {
base: foo,
name: 'bar',
strict: false
};
由前文,判断出 IsPropertyReference(ref) 值为 true,所以 this 值为 GetBase(ref),即为 base value,所以 this 值为 foo
例子:
function foo() {
console.log(this)
}
foo();
分析:
var reference = {
base: EnvironmentRecord,
name: 'foo',
strict: false
}
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.