第一组:非严格模式和严格模式的全局函数
function foo() { console.log(this) } function bar() { 'use strict' console.log(this) } foo() // global bar() // undefined // foo 标识符对应的 Reference var fooReference = { base: EnvironmentRecord, propertyName: 'foo', strict: false } // bar 标识符对应的 Reference var barReference = { base: EnvironmentRecord, propertyName: 'bar', strict: true }上述代码中,对于 fooReference,根据函数调用规范可知其 this = getThisValue(fooReference) = GetBase(fooReference).ImplicitThisValue() = undefined,而 barReference 也是一样。
但为什么 foo() 输出的是 global 全局对象而不是 undefined 呢?这是因为在非严格模式下, 当 this 的值为 undefined 时,会被隐式转换为全局对象。而在严格模式下,指定的 this 不再被封装为对象。
第二组:对象的属性访问
var foo = { bar: function () { console.log(this) } } foo.bar() // foo // foo 的 bar 属性对应的 Reference var barReference = { base: foo, propertyName: 'bar', strict: false }上述代码中,对于 barReference,根据函数调用规范可知 this = getThisValue(barReference) = GetBase(barReference) = foo
在 foo.bar()中,MemberExpression 计算的结果是 foo.bar,为什么它是一个 Reference 类型呢?
EcmaScript 5.1标准中的 的规范:
11.2.1 属性访问
返回一个 Reference 类型的值,其基值为 baseValue 且其引用名为 propertyNameString, 严格模式标记为 strict.
这里只引用了最后一步,属性访问最终返回的值是一个 Reference 类型。
第三组:非 Reference 类型的函数调用
首先,需要j简单了解一下 方法,其作用是获取 Reference 类型具体的值,返回结果不再是一个 Reference。例如:
var foo = 1 // foo 标识符对应的 Reference var fooReference = { base: EnvironmentRecord, propertyName: 'foo', strict: false } GetValue(fooReference) // 1示例代码:
value = 1 var foo = { value: 2, bar: function () { console.log(this.value) } }; foo.bar(); // 2 (foo.bar)(); // 2 (false || foo.bar)(); // 1 (foo.bar = foo.bar)(); // 1 (foo.bar, foo.bar)(); // 1在上述示例代码中:
对于 (foo.bar),foo.bar 被 () 包住,使用了分组运算符,查看规范 ,可知分组表达式不会调用 GetValue 方法, 所以 (foo.bar)仍旧是一个 Reference 类型,因此 this 为 Reference 类型的 base 对象,即 foo。
对于 (false || foo.bar),有逻辑与算法,查看规范 ,可知二元逻辑运算符调用了 GetValue 方法,所以false || foo.bar不再是一个 Reference 类型,因此 this 为 undefined,非严格模式下,被隐式转化为 global 对象。
对于 (foo.bar = foo.bar),有赋值运算符,查看规范 ,可知简单赋值调用了 GetValue 方法,所以foo.bar = foo.bar不再是一个 Reference 类型,因此 this 为 undefined,非严格模式下,被隐式转化为 global 对象。
对于 (foo.bar, foo.bar),有逗号运算符,查看规范 ,可知逗号运算符调用了 GetValue 方法,所以foo.bar, foo.bar不再是一个 Reference 类型,因此 this 为 undefined,非严格模式下,被隐式转化为 global 对象。
3.总结
在全局环境(全局执行上下文)中(在任何函数体外部的代码),this 始终指向全局对象
在函数环境(函数执行上下文)中,绝大多数情况,函数的调用方式决定了 this 的值,这与调用函数的()左侧的部分 MemberExpression 的解释执行的结果的类型是不是 Reference 类型直接关联。
4.参考
深入理解JavaScript系列(10):JavaScript核心(晋级高手必读篇)
深入理解JavaScript系列(13):This? Yes,this!
JavaScript深入之从ECMAScript规范解读this
ECMAScript5.1中文版
ECMAScript 5.1 pdf(英)