当我想了解这样的事情时,我发现将它逐步分解是有帮助的。
o.foo
着眼于o
对象,并发现了一个名为foo
属性。它返回一个引用属性,不管它可能是什么。在这种情况下,o.foo
属性是对函数foo
的引用。
p.foo = o.foo
取自上面的结果(对函数foo
的引用),在p
对象中创建一个属性,该对象也被命名为foo
。所以现在p.foo
也是foo
函数的参考,与o.foo
完全一样。
- 该表达式包含在圆括号中,因此现在您可以在
=
符号的左侧或p.foo
的左侧找到它,这是(作为提醒)仍然是对foo
函数的引用。
- 现在我们在最后找到
()
。这会调用我们现有的功能。这是foo
函数。特别请注意,我们是而不是调用p.foo()
。这将是一个方法调用的功能,p.foo
是一个参考,所以在该功能中,this
将被设置为p
。但我们没有这样做。我们只是调用(p.foo = o.foo)
返回的任何函数。与以前一样,这与foo
函数的功能相同,但我们现在已经失去了与o
对象或p
对象之间的任何连接。
- 因此,当我们在最后打电话时,我们只是调用
foo
函数,而不将this
设置为任何特定对象。因此,当我们拨打电话时,this
设置为undefined
。
- 但我们不是在
strict
模式下运行,所以JavaScript的“有益”不希望给我们一个未定义this
,因此它设置this
在浏览器中的window
对象或节点的global
对象。我们之前做过var a = 2;
。因此window
或global
对象实际上现在具有名为a
的属性,并且该属性的值为2
。
- 因此,现在当我们做
console.log(this.a)
时,我们从window
或global
对象中选取a
属性。该值为2
。
如果所有这些代码没有在全局级运行,而是在一个函数内呢?那么会发生什么?
function test() {
function foo() {
console.log(this.a);
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // was 2, but now is undefined
}
test();
现在,当我们调用console.log(this.a);
内foo
,this
还是指window
或global
对象。但是,当我们设置var a = 2;
时,我们不再设置全球财产。我们只是创建一个局部变量。 window.a
或global.a
是undefined
(除非其他代码先前设置了它)。
严格模式避免了一些这种古怪。如果我们将'use strict';
置于代码的顶部,它将以严格模式编译。现在,当我们在最后调用foo
函数(又不是方法!)的最后一个函数调用时,现在将this
设置为undefined
而不是window
或global
。因此,当我们尝试拨打console.log(this.a)
时,代码失败,因为this
与undefined
相同,而undefined
不具有(也不可能)具有a
属性。
让我们试一下:
'use strict';
function foo() {
console.log(this.a);
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // was 2 in the original, but now throws an exception
底线,至少在这个特殊的例子:总是用严格的方式!这是你的朋友。
因为赋值评估为右侧的*值*。而不是属性引用,因为方法调用'o.foo()'中的'o.foo'会做。 – Bergi