我有一個註冊事件處理程序的建構子:
function MyConstructor(data, transport) { this.data = data; transport.on('data', function () { alert(this.data); }); } // Mock transport object var transport = { on: function(event, callback) { setTimeout(callback, 1000); } }; // called as var obj = new MyConstructor('foo', transport);
但是,我無法存取回呼內建立的物件的 data
屬性。看起來 this
不會引用創建的對象,而是引用另一個對象。
我還嘗試使用物件方法而不是匿名函數:
function MyConstructor(data, transport) { this.data = data; transport.on('data', this.alert); } MyConstructor.prototype.alert = function() { alert(this.name); };
但它也存在同樣的問題。
如何存取正確的物件?
P粉3114235942023-10-12 09:02:51
綁定 a>()
函數。 bind()
函數function MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
如果您使用的是 Underscore.js - http://underscorejs.org/#bind
transport.on('data', _.bind(function () { alert(this.data); }, this));
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
P粉9680081752023-10-12 00:55:03
此內容您應該了解
this
(又稱「上下文」)是每個函數內的特殊關鍵字,其值只取決於如何呼叫函數,而不是如何/何時/何處調用它被定義了。它不像其他變數一樣受到詞法作用域的影響(箭頭函數除外,見下文)。以下是一些範例:
function foo() { console.log(this); } // normal function call foo(); // `this` will refer to `window` // as object method var obj = {bar: foo}; obj.bar(); // `this` will refer to `obj` // as constructor function new foo(); // `this` will refer to an object that inherits from `foo.prototype`
要了解有關此
的更多信息,請查看MDN 文件。
this
#ECMAScript 6 引入了箭頭函數,可以將其視為 lambda 函數。它們沒有自己的 this
綁定。相反,this
就像普通變數一樣在範圍內尋找。這意味著您不必呼叫 .bind
。這並不是他們唯一的特殊行為,請參閱 MDN 文件以獲取更多資訊。
function MyConstructor(data, transport) { this.data = data; transport.on('data', () => alert(this.data)); }
這個
#您實際上不想特別訪問this
,而是訪問它引用的物件。這就是為什麼一個簡單的解決方案是簡單地建立一個也引用該物件的新變數。變數可以有任何名稱,但常見的是 self
和 that
。
function MyConstructor(data, transport) { this.data = data; var self = this; transport.on('data', function() { alert(self.data); }); }
由於 self
是一個普通變量,因此它遵循詞法範圍規則並且可以在回調內部存取。這還有一個優點,就是您可以存取回呼本身的 this
值。
this
- 第 1 部分看起來您無法控制 this
的值,因為它的值是自動設定的,但實際上並非如此。
每個函數都有方法 .bind
[docs],它會傳回一個新函數,其中this
綁定到一個值。函數與您呼叫 .bind
的函數具有完全相同的行為,只是 this
是由您設定的。無論何時或如何呼叫該函數,this
都將始終引用傳遞的值。
function MyConstructor(data, transport) { this.data = data; var boundFunction = (function() { // parenthesis are not necessary alert(this.data); // but might improve readability }).bind(this); // <- here we are calling `.bind()` transport.on('data', boundFunction); }
在本例中,我們將回呼的 this
綁定到 MyConstructor
的 this
的值。
注意:當jQuery 的綁定上下文時,使用jQuery .proxy
[docs]代替。這樣做的原因是這樣您在取消綁定事件回呼時不需要儲存對函數的參考。 jQuery 在內部處理這個問題。
this
- 第 2 部分一些接受回呼的函數/方法也接受回呼的 this
應該引用的值。這基本上與您自己綁定它相同,但是函數/方法會為您完成它。 Array#map
< em>[docs]#就是這樣的方法。它的簽名是:
array.map(callback[, thisArg])
第一個參數是回調,第二個參數是 this
應該要引用的值。這是一個人為的範例:
var arr = [1, 2, 3]; var obj = {multiplier: 42}; var new_arr = arr.map(function(v) { return v * this.multiplier; }, obj); // <- here we are passing `obj` as second argument
注意:是否可以為 this
傳遞值通常在該函數/方法的文件中提到。例如, jQuery 的$.ajax
方法[docs] 描述了一個名為context
的選項:
此問題的另一個常見表現是當物件方法用作回調/事件處理程序時。函數是 JavaScript 中的一等公民,術語「方法」只是函數的通俗術語,函數是物件屬性的值。但該函數沒有指向其「包含」物件的特定連結。
考慮以下範例:
function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = function() { console.log(this.data); };
函數this.method
被指定為點擊事件處理程序,但如果點擊document.body
,記錄的值將是未定義
,因為在在事件處理程序中,this
引用的是document.body
,而不是Foo
的實例。
如同一開始已經提到的,this
指涉的內容取決於函數如何呼叫,而不是如何定義。
如果程式碼如下所示,則函數沒有對該物件的隱式參考可能會更明顯:
function method() { console.log(this.data); } function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = method;
解決方案與上面提到的相同:如果可用,使用.bind
將this
明確綁定到特定值
document.body.onclick = this.method.bind(this);
或透過使用匿名函數作為回調/事件處理程序來明確調用函數作為物件的“方法”,並將物件 (this
) 分配給另一個變數:
var self = this; document.body.onclick = function() { self.method(); };
或使用箭頭函數:
document.body.onclick = () => this.method();