为什么this变了

在微博和知乎上都见过这个问题,就把我在知乎的回答整理搬运过来吧。
先看以下代码:

var name = "The Window";
var object = {
name : "My Object",
getName : function(){
console.log(this.name);
}
};
// 以下输出
object.getName(); // "My Object"
(object.getName)(); // "My Object"
(object.getName = object.getName)(); // "The Window"

第一行的结果大家应该都知道,不多说了。第二行可能有人会有些疑问,先跳过,我先说第三行的。

第三行 『(object.getName = object.getName) 』圆括号里的内容是AssignmentExpression,它的返回值是『GetValue(等号右边的表达式)』。注意这个GetValue是规范中的抽象操作,object.getName经过这个GetValue操作之后就不是Reference type了,丢失了它的this信息。

而第二行实际和第一行是一样的。这个圆括号在规范中叫grouping operator,它不执行GetValue操作,所以函数调用的时候函数知道自己是通过object进行调用的。
(实际上你可以试一下,『(object.foo) = 1)』是合法的语句)

规范中的相应部分:

[1] 关于函数调用的部分,在这里你可以看出来function call在不同情况下对this的处理
http://www.ecma-international.org/ecma-262/7.0/index.html#sec-function-calls-runtime-semantics-evaluation
[2] AssignmentExpression的执行过程 http://www.ecma-international.org/ecma-262/7.0/index.html#sec-assignment-operators-runtime-semantics-evaluation
[3] Grouping operator的执行过程 http://www.ecma-international.org/ecma-262/7.0/index.html#sec-grouping-operator-runtime-semantics-evaluation