Saturday 5 November 2016

javascript - Pass correct "this" context to setTimeout callback?




How do I pass context into setTimeout? I want to call this.tip.destroy() if this.options.destroyOnHide after 1000 ms. How can I do that?



if (this.options.destroyOnHide) {

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


When I try the above, this refers to the window.


Answer



EDIT: In summary, back in 2010 when this question was asked the most common way to solve this problem was to save a reference to the context where the setTimeout function call is made, because setTimeout executes the function with this pointing to the global object:



var that = this;
if (this.options.destroyOnHide) {

setTimeout(function(){ that.tip.destroy() }, 1000);
}


In the ES5 spec, just released a year before that time, it introduced the bind method, this wasn't suggested in the original answer because it wasn't yet widely supported and you needed polyfills to use it but now it's everywhere:



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



The bind function creates a new function with the this value pre-filled.



Now in modern JS, this is exactly the problem arrow functions solve in ES6:



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



Arrow functions do not have a this value of its own, when you access it, you are accessing the this value of the enclosing lexical scope.



HTML5 also standardized timers back in 2011, and you can pass now arguments to the callback function:



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


See also:





No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...