简体   繁体   English

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

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

I'm trying to call a function within an object literal that I created, using the this keyword. 我正在尝试使用this关键字调用我创建的对象文字中的函数。 But an error shows up saying this.doTheMove() is not a function: 但是错误显示出这个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!');

  }
}

Why is there an error? 为什么会出错?

An explanation of what's happening. 对正在发生的事情的解释。 Pointy's answer is good but I want to explain it more generically. Pointy的答案很好,但我想更一般地解释它。 A very good research on this can be found here 可以在这里找到关于this非常好的研究

An event handler is just a callback. 事件处理程序只是一个回调。 You pass it a function and an event to listen on. 你传递一个函数和一个事件来监听。 Interally all it will do is call that function. 它所做的一切就是调用该函数。

Animation.init is just a getter for that function. Animation.init只是该函数的一个getter。 Think of it like this: 可以这样想:

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

So all you've done is passed in 所以你所做的就是传入

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

By default in javascript this === window . 默认情况下在javascript this === window This will refer to the global object if it isn't set to something. 如果没有设置为某个东西,这将引用全局对象。 The net effect is that window.doTheMove is called. 净效果是window.doTheMove被调用。 And that function doesn't exist. 而且这个功能不存在。

In this case since callback is actaully called by an event handler the this object points at the DOM object that triggered the event so your calling node.doTheMove which still doesn't exist. 在这种情况下,由于callback是由事件处理程序调用的,因此this对象指向触发事件的DOM对象,因此您的调用node.doTheMove仍然不存在。

What you wanted to do is wrap it with a reference to Animation. 你想要做的是用动画引用它。

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

This is a function execution and it executes init on Animation . 这是一个函数执行,它在Animation上执行init When you execute it on an object like that then internally this === Animation as you would expect. 当你在这样的对象上执行它然后在内部this === Animation就像你期望的那样。

To sum up. 总结一下。 The issue here is that Animation.init is just a reference to a function. 这里的问题是Animation.init只是对函数的引用。 It has no information about anything else like Pointy mentioned. 它没有像Pointy提到的任何其他信息。

You have to change the way you set that up: 你必须改变你设置的方式:

window.onload = function(){

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

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

}

In JavaScript, the fact that a function happens to be defined as part of an object literal really doesn't mean very much (if anything, in fact). 在JavaScript中,函数恰好被定义为对象文字的一部分的事实实际上并不是非常重要(事实上,如果有的话)。 The reference to Animation.init does get you to the proper function, but the problem is that when the function is later invoked (in response to an actual "click"), the browser calls the function but has no idea that the object "Animation" should be the this reference. Animation.init的引用确实可以使您获得正确的函数,但问题是当稍后调用该函数时(响应实际的“点击”),浏览器调用该函数但不知道对象“动画” “应该是this参考。 Again, the fact that the function was declared as part of the object is of no importance at all here. 同样,函数被声明为对象的一部分这一事实在这里根本不重要。 Therefore, if you want this to be something in particular of your own choosing, then you have to make sure it's set explicitly in code you control. 因此,如果您希望this是您自己选择的特定内容,那么您必须确保在您控制的代码中明确设置它。 The solution above is about the simplest way to do it: it handles the "click" events with an anonymous function that does nothing other than invoke the "init" function via an explicit reference through "Animation". 上面的解决方案是关于最简单的方法:它使用匿名函数处理“click”事件,除了通过“Animation”通过显式引用调用“init”函数之外什么都不做。 That will ensure that this refers to the "Animation" object when "init" runs. 这将确保在“init”运行时this引用“Animation”对象。

Another alternative would be to use the ".bind()" facility that some browsers and frameworks support: 另一种方法是使用某些浏览器和框架支持的“.bind()”工具:

window.onload = function(){

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

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

}

The net effect is almost exactly the same: that call to ".bind()" returns a function that invokes the function on which it was called (that being the "init" function in the "Animation" object), and does so with its first argument as the this reference (the "context" object). 净效果几乎完全相同:对“.bind()”的调用返回一个函数,该函数调用它所调用的函数(即“Animation”对象中的“init”函数),并且它的第一个参数是this引用(“context”对象)。 That's the same thing that we get from the first example, or effectively the same anyway. 这与我们从第一个例子得到的相同,或者无论如何都是有效的。

Here's another nice approach, I think. 我想这是另一种不错的方法。

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

    }
};

Six and a half years later, but I'm hoping my answer can also provide some insight for current and future developers. 六年半之后,我希望我的回答也能为当前和未来的开发者提供一些见解。

I tend to code using literal objects inside of self defined functions, and the original question posted works just fine if another self-executing function is added along with a try and catch statement. 我倾向于使用自定义函数内部的文字对象进行编码,如果添加了另一个自执行函数以及try和catch语句,则发布的原始问题可以正常工作。

It's very important to point out that it's all about scope and context. 指出它是关于范围和背景的非常重要。

Please correct any drawbacks or provide more effective suggestions of using this method. 请更正任何缺点或提供使用此方法的更有效建议。

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

})();

You might want to use the portotype base approach: 您可能希望使用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