Javascriptクラスがあり、各メソッドはQ
promiseを返します。 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
を削除していますか?
this
は、常にメソッドが呼び出されるオブジェクトです。ただし、メソッドをthen()
に渡すときは、呼び出していません!メソッドはどこかに保存され、後でそこから呼び出されます。 this
を保持する場合は、次のようにする必要があります。
.then(() => this.method2())
または、ES6以前の方法で行う必要がある場合は、this
を保存する必要があります。
var that = this;
// ...
.then(function() { that.method2() })
Promiseハンドラーは、デフォルトでグローバルオブジェクト(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
コンテキストが何であるかを明示的に述べています。これらは常に前の2つよりも優先されます。この例では、関数参照を渡しているため、呼び出しの際には、グローバル関数またはコンテキストのない関数であることが暗示されています。 .bind
を使用すると、this
が明示的に設定されている新しい関数を作成することでこれを解決します。
*これは、非厳密モードでのみ当てはまります。厳格モードでは、this
はundefined
に設定されます。
**使用している関数が手動でバインドされていないと仮定します。
関数がそのコンテキスト(this
)を取得する1つの方法は、それらが呼び出されるオブジェクトからです(そのため、method1
には正しいコンテキストがあります-this
で呼び出されます)。関数自体への参照をthen
に渡します。 then
の実装は次のように見えると想像できます。
function then( callback ) {
// assume 'value' is the recently-fulfilled promise value
callback(value);
}
その例では、callback
は関数への参照です。コンテキストはありません。既に述べたように、それを渡す前に関数をコンテキストにバインドすることで、それを回避できます。