簡體   English   中英

在javascript對象文字符號聲明中調用函數

[英]Calling a function in javascript object literal notation declaration

我正在嘗試使用this關鍵字調用我創建的對象文字中的函數。 但是錯誤顯示出這個this.doTheMove()不是函數:

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', Animation.init, false);

}

var Animation = {
  init: function(){

     this.doTheMove(); // I'm calling the function here, but it gives an error.

  },
  doTheMove: function(){

    alert('Animation!');

  }
}

為什么會出錯?

對正在發生的事情的解釋。 Pointy的答案很好,但我想更一般地解釋它。 可以在這里找到關於this非常好的研究

事件處理程序只是一個回調。 你傳遞一個函數和一個事件來監聽。 它所做的一切就是調用該函數。

Animation.init只是該函數的一個getter。 可以這樣想:

var callback = Animation.init
animBtn.addEventListener('click', callback, false);
...
// internal browser event handler
handler() {
   // internal handler does stuff
   ...
   // Oh click event happened. Let's call that callback
   callback();
}

所以你所做的就是傳入

var callback = function(){
   this.doTheMove(); // I'm calling the function here, but it gives an error.
}

默認情況下在javascript this === window 如果沒有設置為某個東西,這將引用全局對象。 凈效果是window.doTheMove被調用。 而且這個功能不存在。

在這種情況下,由於callback是由事件處理程序調用的,因此this對象指向觸發事件的DOM對象,因此您的調用node.doTheMove仍然不存在。

你想要做的是用動畫引用它。

var callback = function() {
    Animation.init();
}

這是一個函數執行,它在Animation上執行init 當你在這樣的對象上執行它然后在內部this === Animation就像你期望的那樣。

總結一下。 這里的問題是Animation.init只是對函數的引用。 它沒有像Pointy提到的任何其他信息。

你必須改變你設置的方式:

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', function() { Animation.init(); }, false);

}

在JavaScript中,函數恰好被定義為對象文字的一部分的事實實際上並不是非常重要(事實上,如果有的話)。 Animation.init的引用確實可以使您獲得正確的函數,但問題是當稍后調用該函數時(響應實際的“點擊”),瀏覽器調用該函數但不知道對象“動畫” “應該是this參考。 同樣,函數被聲明為對象的一部分這一事實在這里根本不重要。 因此,如果您希望this是您自己選擇的特定內容,那么您必須確保在您控制的代碼中明確設置它。 上面的解決方案是關於最簡單的方法:它使用匿名函數處理“click”事件,除了通過“Animation”通過顯式引用調用“init”函數之外什么都不做。 這將確保在“init”運行時this引用“Animation”對象。

另一種方法是使用某些瀏覽器和框架支持的“.bind()”工具:

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', Animation.init.bind(Animation); }, false);

}

凈效果幾乎完全相同:對“.bind()”的調用返回一個函數,該函數調用它所調用的函數(即“Animation”對象中的“init”函數),並且它的第一個參數是this引用(“context”對象)。 這與我們從第一個例子得到的相同,或者無論如何都是有效的。

我想這是另一種不錯的方法。

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', Animation.init, false);

};

var Animation = {
    init: function(){

        Animation.doTheMove(); // This will work, but your IDE may complain...

    },
    doTheMove: function(){

        alert('Animation!');

    }
};

六年半之后,我希望我的回答也能為當前和未來的開發者提供一些見解。

我傾向於使用自定義函數內部的文字對象進行編碼,如果添加了另一個自執行函數以及try和catch語句,則發布的原始問題可以正常工作。

指出它是關於范圍和背景的非常重要。

請更正任何缺點或提供使用此方法的更有效建議。

(function() {

console.log(this);  // window object

    var animation = {
        init: function() {
            this.doTheMove();
        },
        doTheMove: function() {
            alert("Animation");
            console.log(animation); // animation object
        }
    };

    (function() {
        try {
            console.log("animation.init"); // animation.init function
            animation.init();
        } catch(e) {
            console.log("Error is: " + e);
        }
    })();

})();

您可能希望使用portotype基本方法:

// generate a prototype object which can be instantiated
var Animation = function() { this.doTheMove(); }
Animation.prototype.doTheMove = function() {
    // if the object has only one method, the whole code could be moved to 
    // var Animation = function() {...} above
    alert('Animation!'); 
}

Animation.prototype.otherMethod = function(param1, param2) {
  // ...
}


// run the code onload
window.onload = function(){
  var animBtn = document.getElementById('startAnim');
  animBtn.addEventListener('click', new Animation(), false);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM