在 javascript 对象文字表示法声明中调用函数

发布于 2024-10-14 15:02:10 字数 483 浏览 6 评论 0原文

我正在尝试使用 this 关键字调用我创建的对象文字中的函数。但出现错误,指出 this.doTheMove() is not a function:

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

  }
}

为什么会出现错误?

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

明明#如月 2024-10-21 15:02:10

对正在发生的事情的解释。 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 提到的其他任何信息。

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

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:

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.doTheMove is called. 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.

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. When you execute it on an object like that then internally this === Animation as you would expect.

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

中性美 2024-10-21 15:02:10

您必须更改设置方式:

window.onload = function(){

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

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

}

在 JavaScript 中,函数恰好被定义为对象文字的一部分这一事实实际上并没有多大意义(如果有的话,事实上)。对 Animation.init 的引用确实可以让您找到正确的函数,但问题是当稍后调用该函数时(响应实际的“点击”),浏览器调用该函数,但不知道对象“Animation”应该是 this 引用。同样,函数被声明为对象的一部分这一事实在这里并不重要。因此,如果您希望 this 成为您自己选择的特定内容,那么您必须确保它在您控制的代码中显式设置。上面的解决方案是最简单的方法:它使用匿名函数处理“单击”事件,该匿名函数除了通过“动画”的显式引用调用“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”对象)来执行此操作。这与我们从第一个示例中得到的结果相同,或者实际上是相同的。

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.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. 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. 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 this refers to the "Animation" object when "init" runs.

Another alternative would be to use the ".bind()" facility that some browsers and frameworks support:

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). That's the same thing that we get from the first example, or effectively the same anyway.

酷遇一生 2024-10-21 15:02:10

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

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

    }
};

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

    }
};
∝单色的世界 2024-10-21 15:02:10

您可能想使用 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);
}

You might want to use the portotype base approach:

// 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);
}
寄居者 2024-10-21 15:02:10

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

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

})();

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.

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

})();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文