如何将上下文传递到 setTimeout
?如果 this.options.destroyOnHide
在 1000 毫秒后,我想调用 this.tip.destroy()
。我怎样才能做到这一点?
if (this.options.destroyOnHide) {
setTimeout(function() { this.tip.destroy() }, 1000);
}
当我尝试上述方法时,this
指的是窗口。
编辑: 总之,早在 2010 年问这个问题时,解决此问题的最常见方法是保存对执行 setTimeout
函数调用的上下文的引用,因为 setTimeout
使用指向全局对象的 this
执行函数:
var that = this;
if (this.options.destroyOnHide) {
setTimeout(function(){ that.tip.destroy() }, 1000);
}
在一年前刚刚发布的 ES5 规范中,它引入了 bind
method,这在最初的答案中没有被建议,因为它还没有得到广泛的支持,你需要 polyfill 来使用它,但现在它无处不在:
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 也 standardized timers 早在 2011 年,您现在可以将参数传递给回调函数:
if (this.options.destroyOnHide) {
setTimeout(function(that){ that.tip.destroy() }, 1000, this);
}
也可以看看:
setTimeout - 'this' 问题
函数包装器@CMS 有现成的快捷方式(语法糖)回答。 (下面假设您想要的上下文是 this.tip
。)
ECMAScript 2015(所有常见的浏览器和智能手机,Node.js 5.0.0+)
对于几乎所有 javascript 开发(2020 年),您都可以使用 胖箭头函数,即 part of the ECMAScript 2015 (Harmony/ES6/ES2015) specification。
与函数表达式相比,箭头函数表达式(也称为胖箭头函数)具有更短的语法,并且在词法上绑定了 this 值 [...]。
(param1, param2, ...rest) => { statements }
在你的情况下,试试这个:
if (this.options.destroyOnHide) {
setTimeout(() => { this.tip.destroy(); }, 1000);
}
ECMAScript 5(旧版浏览器和智能手机,Node.js)和 Prototype.js
如果您以 browser compatible with ECMA-262, 5th edition (ECMAScript 5) 或 Node.js(2020 年)表示所有常见浏览器以及旧版浏览器为目标,则可以使用 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 如果您想要自定义向后兼容性(但请遵守注意事项)。
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(...)
1,2
bind 将一个函数绑定到一个对象,这意味着无论何时调用该函数,this 的值都会是该对象。或者,将参数绑定到函数以预填充它们,也称为部分应用。
_.bind(function, object, [*arguments])
在你的情况下,试试这个:
if (this.options.destroyOnHide) {
setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}
bind jquery underscore.js ecmascript-5 prototypejs node.js
func.bind(context...)
?我错过了什么吗?
var boundFn = fn.bind(this); boundFn(); boundFn();
。
在 Internet Explorer 以外的浏览器中,您可以在延迟后将参数一起传递给函数:
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
所以,你可以这样做:
var timeoutID = window.setTimeout(function (self) {
console.log(self);
}, 500, this);
这在性能方面优于范围查找(将 this
缓存到超时/间隔表达式之外的变量中),然后创建闭包(通过使用 $.proxy
或 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);
}
});
@*/
注意:这在 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);
如果您使用 underscore
,则可以使用 bind
。
例如
if (this.options.destroyOnHide) {
setTimeout(_.bind(this.tip.destroy, this), 1000);
}
如果您使用的是 TypeScript,则可以将函数作为参数传递,如下所示:
setTimeout(this.tip.destroy, 1000);
并且 this
上下文将被分配,就好像您将调用封装在 JavaScript 中的箭头函数中一样。
this
传递给该函数,那么您已经解决了这种情况下的这个问题,对于 map()、forEach() 等,使用更少的代码、更少的 CPU 周期和更少的内存. ***见:Misha Reyzlin 的回答。