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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4820163/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 14:58:48  来源:igfitidea点击:

Calling a function in javascript object literal notation declaration

javascriptobject-literal

提问by Shaoz

I'm trying to call a function within an object literal that I created, using the thiskeyword. But an error shows up saying this.doTheMove()is not a function:

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

  }
}

Why is there an error?

为什么会出现错误?

采纳答案by Raynos

An explanation of what's happening. Pointy's answer is good but I want to explain it more generically. A very good research on thiscan be found here

对正在发生的事情的解释。Pointy 的回答很好,但我想更笼统地解释一下。一个很好的研究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. Think of it like 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();
}

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. This will refer to the global object if it isn't set to something. The net effect is that window.doTheMoveis called. And that function doesn't exist.

默认在 javascript 中this === window。如果它没有设置为什么,这将引用全局对象。净效应window.doTheMove就是所谓的。而且这个功能不存在。

In this case since callbackis actaully called by an event handler the thisobject points at the DOM object that triggered the event so your calling node.doTheMovewhich still doesn't exist.

在这种情况下,由于callback由事件处理程序实际调用,该this对象指向触发事件的 DOM 对象,因此您的调用node.doTheMove仍然不存在。

What you wanted to do is wrap it with a reference to Animation.

您想要做的是使用对 Animation 的引用来包装它。

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

This is a function execution and it executes initon Animation. When you execute it on an object like that then internally this === Animationas you would expect.

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

To sum up. The issue here is that Animation.initis just a reference to a function. It has no information about anything else like Pointy mentioned.

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

回答by 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). The reference to Animation.initdoesget 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 thisreference. Again, the fact that the function was declared as part of the object is of no importance at all here. Therefore, if you want thisto be something in particular of your own choosing, then you have to make sure it's set explicitly in code you control. 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". That will ensure that thisrefers to the "Animation" object when "init" runs.

在 JavaScript 中,函数恰好被定义为对象字面量的一部分这一事实实际上并没有多大意义(如果有的话,事实上)。对的引用Animation.init确实让您获得了正确的函数,但问题是当稍后调用该函数时(响应实际的“点击”),浏览器调用该函数但不知道对象“Animation”应该是该this参考。同样,函数被声明为对象的一部分这一事实在这里根本不重要。因此,如果你想this要成为您自己选择的特别内容,那么您必须确保在您控制的代码中明确设置它。上面的解决方案是最简单的方法:它使用匿名函数处理“click”事件,该函数除了通过“Animation”通过显式引用调用“init”函数之外什么都不做。这将确保this在“init”运行时引用“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 thisreference (the "context" object). That's the same thing that we get from the first example, or effectively the same anyway.

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

回答by StephenKC

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

    }
};

回答by SC87

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

})();

回答by Spliffster

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