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

Jam*_*ead 226 javascript callback this settimeout

如何将上下文传递给setTimeout?我想打电话this.tip.destroy(),如果this.options.destroyOnHide在1000毫秒.我怎样才能做到这一点?

if (this.options.destroyOnHide) {
     setTimeout(function() { this.tip.destroy() }, 1000);
} 
Run Code Online (Sandbox Code Playgroud)

当我尝试以上时,this指的是窗口.

CMS*_*CMS 308

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

var that = this;
if (this.options.destroyOnHide) {
     setTimeout(function(){ that.tip.destroy() }, 1000);
} 
Run Code Online (Sandbox Code Playgroud)

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

if (this.options.destroyOnHide) {
     setTimeout(function(){ this.tip.destroy() }.bind(this), 1000);
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 有用.我用jsbin脚本测试了这个概念:http://jsbin.com/etise/7/edit (3认同)

Joe*_*rra 221

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


ECMAScript 5(当前浏览器,Node.js)和Prototype.js

如果您的目标浏览器与ECMA-262,第5版(ECMAScript 5)Node.js 兼容,则可以使用Function.prototype.bind.您可以选择传递任何函数参数来创建部分函数.

fun.bind(thisArg[, arg1[, arg2[, ...]]])
Run Code Online (Sandbox Code Playgroud)

再次,在您的情况下,试试这个:

if (this.options.destroyOnHide) {
    setTimeout(this.tip.destroy.bind(this.tip), 1000);
}
Run Code Online (Sandbox Code Playgroud)

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

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


ECMAScript 2015(部分浏览器,Node.js 5.0.0+)

对于尖端开发(2015),您可以使用胖箭头函数,它们是ECMAScript 2015(Harmony/ES6/ES2015)规范(示例)的一部分.

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

(param1, param2, ...rest) => { statements }
Run Code Online (Sandbox Code Playgroud)

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

if (this.options.destroyOnHide) {
    setTimeout(() => { this.tip.destroy(); }, 1000);
}
Run Code Online (Sandbox Code Playgroud)

jQuery的

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

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

$.proxy(function, context[, additionalArguments])
Run Code Online (Sandbox Code Playgroud)

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

if (this.options.destroyOnHide) {
    setTimeout($.proxy(this.tip.destroy, this.tip), 1000);
}
Run Code Online (Sandbox Code Playgroud)

Underscore.js,lodash

它的问世在Underscore.js,以及lodash,如_.bind(...)1,2

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

_.bind(function, object, [*arguments])
Run Code Online (Sandbox Code Playgroud)

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

if (this.options.destroyOnHide) {
    setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}
Run Code Online (Sandbox Code Playgroud)


Mis*_*lin 30

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

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
Run Code Online (Sandbox Code Playgroud)

所以,你可以这样做:

var timeoutID = window.setTimeout(function (self) {
  console.log(self); 
}, 500, this);
Run Code Online (Sandbox Code Playgroud)

这在性能方面优于范围查找(缓存this到超出/间隔表达式之外的变量),然后创建闭包(通过使用$.proxyFunction.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);
    }
});
@*/
Run Code Online (Sandbox Code Playgroud)


gum*_*ins 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);
Run Code Online (Sandbox Code Playgroud)