将正确的“this”上下文传递给setTimeout回调?

时间:2010-01-25 04:44:21

标签: javascript callback this settimeout

如何将上下文传递到setTimeout?我希望在1000毫秒后调用this.tip.destroy() if this.options.destroyOnHide。我怎么能这样做?

if (this.options.destroyOnHide) {
     setTimeout(function() { this.tip.destroy() }, 1000);
} 

当我尝试上述操作时,this指向窗口。

6 个答案:

答案 0 :(得分:278)

您需要保存对进行setTimeout函数调用的上下文的引用,因为setTimeout执行函数时this指向全局对象:

var that = this;
if (this.options.destroyOnHide) {
     setTimeout(function(){that.tip.destroy()}, 1000);
} 

您可以通过以下方式轻松证明setTimeoutthis设置为全局对象。

(function () {
  alert(this); // alerts hello
  setTimeout(function(){
    alert(this == window); // true
  }, 1000);
}).call("hello");

另见:

答案 1 :(得分:220)

函数包装器@CMS回答了现成的快捷方式(语法糖)。 (下面假设您想​​要的上下文是this.tip。)


ECMAScript 5current browsers,Node.js)和Prototype.js

如果您定位browser compatible with ECMA-262, 5th edition (ECMAScript 5)Node.js,则可以使用Function.prototype.bind。您可以选择传递任何函数参数来创建partial functions

fun.bind(thisArg[, arg1[, arg2[, ...]]])

同样,在你的情况下,试试这个:

if (this.options.destroyOnHide) {
    setTimeout(this.tip.destroy.bind(this.tip), 1000);
}

同样的功能也是implemented in Prototype(任何其他库?)。

Function.prototype.bind can be implemented like this如果您想要自定义向后兼容性(但请注意注释)。


ECMAScript 2015some browsers,Node.js 5.0.0 +)

对于尖端开发(2015),您可以使用胖箭头函数,它们是part of the ECMAScript 2015 (Harmony/ES6/ES2015) specificationexamples)。

  

与函数表达式相比,arrow function expression(也称为胖箭头函数)具有更短的语法,并且词法绑定this值[...]。

(param1, param2, ...rest) => { statements }

在你的情况下,试试这个:

if (this.options.destroyOnHide) {
    setTimeout(() => { this.tip.destroy(); }, 1000);
}

jQuery

如果您已经在使用jQuery 1.4+,那么有一个现成的函数可以显式设置函数的this上下文。

  

jQuery.proxy():获取一个函数并返回一个始终具有特定上下文的新函数。

$.proxy(function, context[, additionalArguments])

在你的情况下,试试这个:

if (this.options.destroyOnHide) {
    setTimeout($.proxy(this.tip.destroy, this.tip), 1000);
}

Underscore.jslodash

它可以在Underscore.js和lodash中使用,_.bind(...) 12

  

bind将一个函数绑定到一个对象,这意味着无论何时调用该函数,this的值都将成为对象。 (可选)将参数绑定到函数以预填充它们,也称为部分应用程序。

_.bind(function, object, [*arguments])

在你的情况下,试试这个:

if (this.options.destroyOnHide) {
    setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}

答案 2 :(得分:30)

在Internet Explorer以外的浏览器中,您可以在延迟后一起将参数传递给函数:

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

所以,你可以这样做:

var timeoutID = window.setTimeout(function (self) {
  console.log(self); 
}, 500, this);

这在性能方面优于范围查找(将this缓存到超出/间隔表达式之外的变量中),然后创建一个闭包(使用$.proxy或{{1 }})。

使其在Webreflection的IE中运行的代码:

Function.prototype.bind

答案 3 :(得分:3)

注意:这在IE中不起作用

var ob = {
    p: "ob.p"
}

var p = "window.p";

setTimeout(function(){
    console.log(this.p); // will print "window.p"
},1000); 

setTimeout(function(){
    console.log(this.p); // will print "ob.p"
}.bind(ob),1000);

答案 4 :(得分:2)

如果您使用的是underscore,则可以使用bind

E.g。

if (this.options.destroyOnHide) {
     setTimeout(_.bind(this.tip.destroy, this), 1000);
}

答案 5 :(得分:0)

如果您使用的是 TypeScript,则可以将函数作为参数传递,如下所示:

setTimeout(this.tip.destroy, 1000);

并且 this 上下文将被分配,就像您将调用封装在 JavaScript 中的箭头函数中一样。