面试系列原地址 gitee.com/gusiil/fein…,持续更新中
this
简单的理解
我们先简单的理解 this 指向: this 最终指向调用它的对象
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
foo.bar() // 2
深入理解
如果我们用这个方法解释下以下的情况了
(foo.bar)() // 2
(foo.bar = foo.bar)() // 1
(false || foo.bar)() // 1
(foo.bar, foo.bar)() // 1
这种情况的加入,会让上述解释变得很牵强附会,这是因为上述解释本身就是片面的
我们从 ECMAScript 5 规范说起
Types
ECMAScript 规范将类型分为 语言类型 和 规范类型
-
语言类型是使用者使用的基本类型和引用类型
-
规范类型是用来描述语言结构和语言类型的,即
它们是为了更好地描述语言的底层行为逻辑才存在的
但并不存在于实际的 js 代码中。
Reference
Reference 类型就是用来解释诸如 delete、typeof 以及赋值等操作行为的 规范类型
Reference 由三部分组成
- base: 属性所处对象或者环境,
this所在 - name: 属性名
- strict: 是否是严格模式
而且规范中还提供了获取 Reference 组成部分的方法,比如 GetBase 和 IsPropertyReference。
- GetBase: 返回 base
- IsPropertyReference:如果 base value 是一个对象,就返回 true
确立 this 值
规范文本就不展开了,直接给结论
- 计算
MemberExpression结果,赋值ref - 判断
ref结果是不是一个Reference类型- 如果是
2.1IsPropertyReference(ref)是 true,this等于GetBase(ref)
2.2IsPropertyReference(ref)是 false,this等于ImplicitThisValue(ref) - 如果不是,this 为 undefined
- 如果是
ImplicitThisValue 方法始终返回 undefined
MemberExpression 它可以简单的理解为()左边的表达式
下面解释以上代码
(foo.bar)() // 2
// foo.bar 是Reference 但IsPropertyReference为false,它 的base是个环境记录,因此返回 undefined,非严格模式就是 window
(foo.bar = foo.bar)() // 1
// 有赋值操作符, 返回的值不是 Reference 类型
(false || foo.bar)() // 1
// 有逻辑符, 返回的值不是 Reference 类型
(foo.bar, foo.bar)() // 1
// 有逗号操作符,返回的值不是 Reference 类型
以上运算符本质上调用了 GetValue ,从 Reference 类型获取对应值的方法,因此都不会是 Reference
结语
简单的解释本质上是片面的,需要结合 Reference 规范类型,才能解释清楚 this 的具体指向