Why is 'this' undefined inside class method when using promises?

SteamDev picture SteamDev · Jan 21, 2016 · Viewed 69.2k times · Source

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?

Answer

lex82 picture lex82 · Jan 21, 2016

this is always the object the method is called on. However, when passing the method to then(), you are not calling it! The method will be stored somewhere and called from there later. If you want to preserve this, you will have to do it like this:

.then(() => this.method2())

or if you have to do it the pre-ES6 way, you need to preserve this before:

var that = this;
// ...
.then(function() { that.method2() })