Почему " это " не определено внутри метода класса при использовании обещаний? [дубликат]


этот вопрос уже есть ответ здесь:

  • setTimeout и "это" в JavaScript 5 ответов

у меня есть класс, и каждый метод возвращает Q обещание. Я хочу знать, почему this не определено в method2 и method3. Есть ли более правильный способ написать этот код?

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;
};

я могу исправить с помощью bind:

function MyClass(opts){
  this.options = opts;

  return this.method1()
    .then(this.method2.bind(this))
    .then(this.method3.bind(this));
}

но не совсем уверен, почему bind необходимо; это .then() убийство this выкл?

4 65

4 ответа:

this всегда является объектом, на который вызывается метод. Однако при передаче метода в then(), вы не называете это! Метод будет сохранен где-то и вызван оттуда позже. Если вы хотите сохранить this, вам придется сделать это так:

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

или если вы должны сделать это до ES6 способ, вы должны сохранить this перед:

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

обработчики обещаний вызываются в контексте глобального объекта (window) по умолчанию. Когда в строгом режиме (use strict;), контекст undefined. Вот что происходит с method2 и method3.

;(function(){
  'use strict'
  Promise.resolve('foo').then(function(){console.log(this)}); // undefined
}());

;(function(){
  Promise.resolve('foo').then(function(){console.log(this)}); // window
}());

на method1, ты называешь method1 как this.method1(). Этот способ вызова его вызывает его в контексте this объект, который является экземпляром. Вот почему контекст внутри method1 - это экземпляр.

по сути, вы передаете ему ссылку на функцию без контекстной ссылки. Элемент this контекст определяется несколькими способами:

  1. неявно. Вызов глобальной функции или функции без привязки предполагает глобальный контекст.*
  2. по прямой ссылке. Если вы позвоните myObj.f() затем myObj будет this контексте.**
  3. ручной переплет. Это класс функций, таких как .bind и .apply. Эти вы явно государство какое то this контекст. Они всегда имеют приоритет над предыдущими двумя.

в вашем примере вы передаете ссылку на функцию, поэтому при ее вызове подразумевается, что она является глобальной функцией или без контекста. Используя .bind решает эту проблему путем создания новой функции, где this явно.

*это верно только в нестрогом режиме. В строгом режиме, this установлено значение undefined.

**предполагая, что функция, которую вы использование не было привязано вручную.

один из способов функции получают свой контекст (this) от объекта, на котором они вызываются (именно поэтому method1 имеет правильный контекст - он вызывается на this). Вы передаете ссылку на саму функцию в then. Вы можете себе представить, что реализация then выглядит так:

function then( callback ) {

  // assume 'value' is the recently-fulfilled promise value
  callback(value);
}
callback - это ссылка на функцию. У него нет никакого контекста. Как вы уже отметили, Вы можете обойти это, связав функция для контекста, прежде чем передать его затем.