Почему " это " не определено внутри метода класса при использовании обещаний? [дубликат]
этот вопрос уже есть ответ здесь:
- 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 ответа:
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
контекст определяется несколькими способами:
- неявно. Вызов глобальной функции или функции без привязки предполагает глобальный контекст.*
- по прямой ссылке. Если вы позвоните
myObj.f()
затемmyObj
будетthis
контексте.**- ручной переплет. Это класс функций, таких как
.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
- это ссылка на функцию. У него нет никакого контекста. Как вы уже отметили, Вы можете обойти это, связав функция для контекста, прежде чем передать его затем.