I am a little bit confused on how this works, let me post you an example code:
someClass = function() {
this.a = 10;
this.Foo = function() {
console.log(this.a); // will output "10"
setTimeout(this.Bar, 1);
}
this.Bar = function() {
console.log(this.a); // undefined
}
}
var instance = new someClass();
instance.Foo();
My understanding is that this.a is not visible in function Bar if it is called from setTimeout (or some other "handler" type of thing.) What is the common/correct way of solving that?
(I am trying this in Node.js btw)
Thank you.
When passing the function this.Bar as an argument to another function, you need to bind this.Bar to the context you'd like it to be executed with.
If you're using a JS library like jQuery or Underscore.js they already come with that functionality:
setTimeout(_.bind(this.Bar, this), 1);
Here's a simple implementation of a bind function:
var bind = function(scope, fn) {
return function() {
return fn.apply(scope, arguments);
};
}
Update:
As @generalhenry pointed out, node.js already comes with a bind function in (Function.prototype.bind), so you can do this without adding a custom bind function nor an external library:
setTimeout(this.Bar.bind(this), 1);
The problem is that the scope (this) is lost when you pass a function to setTimeout.
Here's the easiest way to fix it, store this as a reference through a closure and use that instead.
// This uses _me_ everywhere for consistency, but the only place that really needs it
// is within the Bar method. But consistency in this case makes your code more change-
// proof, say if someone calls setTimeout(instance.Foo, 1)
someClass = function() {
var me = this;
me.a = 10;
me.Foo = function() {
console.log(me.a); // will output "10"
// setTimeout will cause me.Bar to be called with window as the context
setTimeout(me.Bar, 1);
}
me.Bar = function() {
// so we avoid using _this_ in here
console.log(me.a); // 10
}
}
A slightly more elegant way is to use Function.bind
someClass = function() {
this.a = 10;
this.Foo = function() {
console.log(this.a); // will output "10"
// the bind call will force it to use the first argument as `this`
setTimeout(this.Bar.bind(this), 1);
}
this.Bar = function() {
console.log(this.a); // undefined
}
}