292

如何将上下文传递到setTimeout? 我想this.tip.destroy()this.options.destroyOnHide1000 毫秒后打电话。我怎样才能做到这一点?

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

当我尝试上述方法时,this指的是窗口。

4

6 回答 6

443

编辑:总之,早在 2010 年问这个问题时,解决这个问题的最常见方法是保存对进行setTimeout函数调用的上下文的引用,因为setTimeout执行this指向全局对象的函数:

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

在一年前刚刚发布的 ES5 规范中,它引入了bindmethod,这在最初的答案中没有被建议,因为它还没有得到广泛的支持,你需要 polyfills 来使用它,但现在它无处不在:

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

bind函数使用this预先填充的值创建一个新函数。

现在在现代 JS 中,这正是箭头函数在ES6中解决的问题:

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

箭头函数没有自己的this值,当您访问它时,您访问的this是封闭词法范围的值。

HTML5 在 2011 年还标准化了计时器,您现在可以将参数传递给回调函数:

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

也可以看看:

于 2010-01-25T05:40:08.167 回答
234

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


ECMAScript 2015所有常见的浏览器和智能手机,Node.js 5.0.0+)

对于几乎所有 javascript 开发(2020 年),您都可以使用粗箭头函数,它们是ECMAScript 2015 (Harmony/ES6/ES2015) 规范的一部分。

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

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

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

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

ECMAScript 5旧版浏览器和智能手机,Node.js)和 Prototype.js

如果您的目标浏览器与 ECMA-262 第 5 版 (ECMAScript 5)Node.js兼容(2020 年)意味着所有常见浏览器以及旧版浏览器,您可以使用Function.prototype.bind. 您可以选择传递任何函数参数来创建部分函数

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

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

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

Prototype(任何其他库?)中也实现了相同的功能。

Function.prototype.bind如果您想要自定义向后兼容性,可以这样实现(但请注意注释)。


jQuery

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

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

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

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

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

下划线.js ,lodash

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

bind 将一个函数绑定到一个对象,这意味着无论何时调用该函数,其值都this将是该对象。或者,将参数绑定到函数以预填充它们,也称为部分应用。

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

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

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

于 2012-01-10T08:01:31.110 回答
31

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

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

所以,你可以这样做:

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

就性能而言,这比范围查找(缓存this到超时/间隔表达式之外的变量),然后创建闭包(通过使用$.proxyor Function.prototype.bind)更好。

使其在Webreflection的 IE 中工作的代码:

/*@cc_on
(function (modifierFn) {
  // you have to invoke it as `window`'s property so, `window.setTimeout`
  window.setTimeout = modifierFn(window.setTimeout);
  window.setInterval = modifierFn(window.setInterval);
})(function (originalTimerFn) {
    return function (callback, timeout){
      var args = [].slice.call(arguments, 2);
      return originalTimerFn(function () { 
        callback.apply(this, args) 
      }, timeout);
    }
});
@*/
于 2012-02-15T17:35:59.973 回答
5

注意:这在 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);
于 2014-05-26T12:19:38.803 回答
2

如果你正在使用underscore,你可以使用bind.

例如

if (this.options.destroyOnHide) {
     setTimeout(_.bind(this.tip.destroy, this), 1000);
}
于 2012-10-20T17:18:16.033 回答
0

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

setTimeout(this.tip.destroy, 1000);

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

于 2021-07-03T13:58:18.510 回答