This question already has an answer here:
- setTimeout and “this” in JavaScript 5 answers
I have a javascript class, and each method returns a Q
promise. I want to know why this
is undefined in method2
and method3
. Is there a more correct way to write this code?
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2)
.then(this.method3);
}
MyClass.prototype.method1 = function(){
// ...q stuff...
console.log(this.options); // logs "opts" object
return deferred.promise;
};
MyClass.prototype.method2 = function(method1resolve){
// ...q stuff...
console.log(this); // logs undefined
return deferred.promise;
};
MyClass.prototype.method3 = function(method2resolve){
// ...q stuff...
console.log(this); // logs undefined
return deferred.promise;
};
I can fix this by using bind
:
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2.bind(this))
.then(this.method3.bind(this));
}
But not entirely sure why bind
is necessary; is .then()
killing this
off?
Promise handlers are called in the context of the global object (
window
) by default. When in strict mode (use strict;
), the context isundefined
. This is what's happening tomethod2
andmethod3
.For
method1
, you're callingmethod1
asthis.method1()
. This way of calling it calls it in the context of thethis
object which is your instance. That's why the context insidemethod1
is the instance.Basically, you're passing it a function reference with no context reference. The
this
context is determined in a few ways:myObj.f()
thenmyObj
is going to be thethis
context.**.bind
and.apply
. These you explicitly state what thethis
context is. These always take precedence over the previous two.In your example, you're passing a function reference, so at it's invocation it's implied to be a global function or one without context. Using
.bind
resolves this by creating a new function wherethis
is explicitly set.*This is only true in non-strict mode. In strict mode,
this
is set toundefined
.**Assuming the function you're using hasn't been manually bound.
One way functions get their context (
this
) is from the object on which they are invoked (which is whymethod1
has the right context - it's invoked onthis
). You are passing a reference to the function itself tothen
. You can imagine that the implementation ofthen
looks something like this:In that example
callback
is a reference to your function. It doesn't have any context. As you've already noted you can get around that by binding the function to a context before you pass it to then.this
is always the object the method is called on. However, when passing the method tothen()
, you are not calling it! The method will be stored somewhere and called from there later. If you want to preservethis
, you will have to do it like this:or if you have to do it the pre-ES6 way, you need to preserve
this
before: