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