18

我正在尝试使用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!');

  }
}

为什么会出现错误?

4

5 回答 5

16

对正在发生的事情的解释。Pointy 的回答很好,但我想更笼统地解释一下。一个很好的研究this可以在这里找到

事件处理程序只是一个回调。你向它传递一个函数和一个事件来监听。实际上,它所做的就是调用该函数。

Animation.init 只是该功能的吸气剂。可以这样想:

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();
}

这是一个函数执行,它initAnimation. 当您在这样的对象上执行它时,然后在内部this === Animation按照您的期望。

总结一下。这里的问题是这Animation.init只是对函数的引用。它没有关于Pointy提到的其他任何信息的信息。

于 2011-01-27T18:44:15.407 回答
10

您必须更改设置方式:

window.onload = function(){

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

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

}

在 JavaScript 中,函数恰好被定义为对象字面量的一部分这一事实实际上并没有多大意义(如果有的话,事实上)。的引用Animation.init 确实可以让您找到正确的函数,但问题是当稍后调用该函数时(响应实际的“点击”),浏览器调用该函数但不知道对象“动画”应该是参考this。同样,函数被声明为对象的一部分这一事实在这里根本不重要。因此,如果你想this要特别是您自己选择的东西,那么您必须确保它在您控制的代码中明确设置。上面的解决方案是最简单的方法:它使用匿名函数处理“单击”事件,该函数除了通过“动画”的显式引用调用“init”函数之外什么都不做。这将确保this在“init”运行时引用“动画”对象。

另一种选择是使用某些浏览器和框架支持的“.bind()”工具:

window.onload = function(){

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

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

}

最终效果几乎完全相同:对“.bind()”的调用返回一个函数,该函数调用调用它的函数(即“Animation”对象中的“init”函数),并使用它的第一个参数作为this参考(“上下文”对象)。这与我们从第一个示例中得到的相同,或者实际上相同。

于 2011-01-27T18:20:27.393 回答
1

我认为这是另一种不错的方法。

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!');

    }
};
于 2013-06-20T23:38:54.070 回答
0

您可能希望使用 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);
}
于 2011-01-27T18:24:51.223 回答
0

六年半之后,但我希望我的回答也能为当前和未来的开发人员提供一些见解。

我倾向于在自定义函数中使用文字对象进行编码,如果添加另一个自执行函数以及 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);
        }
    })();

})();
于 2017-08-01T23:16:46.040 回答