如何让 setTimeout 在对象中执行方法?

Tra*_*vis 3 javascript oop settimeout

我想让一个下拉菜单在发生 mouseleave 事件时关闭,经过短暂的延迟。但我很难让它工作。

考虑对象中的以下方法:(我正在使用 jQuery)

myObj = {};

myObj.message = "woot!";

myObj.bindEvents = function() {

        var that = this;

        $("#menuPanel")
            .bind("mouseleave", function() { 

                    that.timer = setTimeout(that.closeMenu,500); 

            });

    }

myObj.closeMenu = function() {

     // close the menu

     alert(this.message);

}
Run Code Online (Sandbox Code Playgroud)

这不起作用。也就是说, this.message 出现未定义。经过一番挖掘,我明白了为什么。:) 'that' 引用在执行时对 setTimeout 内的代码不可用。

我想知道,解决此类问题的“最佳”方法是什么?如何让使用 setTimeout 的方法调用同一个对象中的另一个方法,并且仍然可以访问对象中的属性?

在此先感谢您的帮助。

And*_*y E 5

这里的问题是你正在从它的对象中分离 closeMenu 方法。如果你这样做,你会遇到同样的问题:

var closeMenu = myObj.closeMenu;  // detaching the method from the object
closeMenu();
Run Code Online (Sandbox Code Playgroud)

像这样分离和调用方法意味着它们不再适用于创建它们的对象。在您的示例中,您几乎在做同样的事情:

// Setting the first parameter of setTimeout to be the detached closeMenu method
that.timer = setTimeout(that.closeMenu,500); 
Run Code Online (Sandbox Code Playgroud)

第一种方法的修复方法是使用callorapply方法:

var closeMenu = myObj.closeMenu;  // detaching the method from the object
closeMenu.apply(myObj);
Run Code Online (Sandbox Code Playgroud)

但这不适用于计时器。相反,创建一个匿名函数:

that.timer = setTimeout(function () { that.closeMenu(); },500); 
Run Code Online (Sandbox Code Playgroud)


可能还值得一提bind()——不要与 jQuery 混淆$('#selector').bind()——这种方法已经在各种博客和一些库(Prototype 是最显着的)中流传了一段时间,并最终在ECMAScript 版本 5 中实现

that.timer = setTimeout(that.closeMenu.bind(that),500);
Run Code Online (Sandbox Code Playgroud)

我在我创建的一两个类中使用了类似的方法,因为它只是让事情变得更容易。