首頁  >  問答  >  主體

如何在回調中存取正確的“this”

我有一個註冊事件處理程序的建構子:


#
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粉296080076P粉296080076374 天前531

全部回覆(2)我來回復

  • P粉311423594

    P粉3114235942023-10-12 09:02:51

    以下是在子上下文中存取父上下文的幾種方法 -
    1. 您可以使用綁定() 函數。
    2. 將對 context/this 的引用儲存在另一個變數中(請參閱下面的範例)。
    3. 使用 ES6 箭頭 功能。
    4. 更改程式碼、功能設計和架構 - 為此,您應該掌握設計模式 在 JavaScript 中。

    1.使用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));

    2.將對 context/this 的引用儲存在另一個變數中

    function MyConstructor(data, transport) {
      var self = this;
      this.data = data;
      transport.on('data', function() {
        alert(self.data);
      });
    }
    

    3.箭頭函數

    function MyConstructor(data, transport) {
      this.data = data;
      transport.on('data', () => {
        alert(this.data);
      });
    }
    

    回覆
    0
  • P粉968008175

    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,而是訪問它引用的物件。這就是為什麼一個簡單的解決方案是簡單地建立一個也引用該物件的新變數。變數可以有任何名稱,但常見的是 selfthat

    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 綁定到 MyConstructorthis 的值。

    注意:當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;

    解決方案與上面提到的相同:如果可用,使用.bindthis明確綁定到特定值

    document.body.onclick = this.method.bind(this);

    或透過使用匿名函數作為回調/事件處理程序來明確調用函數作為物件的“方法”,並將物件 (this) 分配給另一個變數:

    var self = this;
    document.body.onclick = function() {
        self.method();
    };

    或使用箭頭函數:

    document.body.onclick = () => this.method();

    回覆
    0
  • 取消回覆