在javascript对象文字符号声明中调用函数

时间:2011-01-27 18:13:56

标签: javascript object-literal

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

  }
}

为什么会出错?

5 个答案:

答案 0 :(得分:16)

对正在发生的事情的解释。 Pointy的答案很好,但我想更一般地解释它。可以找到关于this的非常好的研究here

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

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

这是一个函数执行,它在init上执行Animation。当您在像这样的对象上执行它时,就像您期望的那样在内部this === Animation执行它。

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

答案 1 :(得分:10)

您必须更改设置方式:

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”对象)。这与我们从第一个例子得到的一样,或者无论如何都是有效的。

答案 2 :(得分: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!');

    }
};

答案 3 :(得分:0)

您可能希望使用基于原型的方法:

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

答案 4 :(得分: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);
        }
    })();

})();