當我想了解這樣的事情時,我發現將它逐步分解是有幫助的。
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