2016-01-21 5 views
51

私はjavascriptクラスを持っており、各メソッドはQという約束を返します。私はなぜthismethod2method3に未定義であるか知りたいと思っています。このコードを書く正しい方法はありますか?約束を使っているときにクラスメソッドの中で 'this'が定義されていないのはなぜですか?

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

+0

bind()を使用すると、paramsによって渡されるスコープとまったく同じ別の関数が作成されます。あなたの最後の質問に答えるだけですが、Mozilaのドキュメントをご覧ください:https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Function/bind –

+0

ちょっとした[this](http://stackoverflow.com/questions/34930771/why-is-this-undefined-inside-class-method-when-using-promises)[that](http:// /image/gif/paws/97920/settimeout-and-this-in-javascript)? 私はまったく同じ質問を出しましたが、これは[that](http://stackoverflow.com/questions/591269/settimeout-and-this-in-javascript)で回答されませんでした。私は既に知っている(http://stackoverflow.com/questions/591269/settimeout-and-this-in-javascript)が、私は約束、ES6クラス、そして 'これ 'の用語に来ている。 – toszter

+0

それは密接に関連していますが、これはこの質問の重複ではありません:http://stackoverflow.com/questions/591269/settimeout-and-this-in-javascriptまたは "なぜリンゴは木から落ちますか?" "なぜ私はテーブルを傾けたときにカードの家が崩壊するのですか?" – lex82

答えて

71

thisは常にメソッドが呼び出されるオブジェクトです。しかし、メソッドをthen()に渡すと、あなたはそれを呼び出すことはありません!メソッドはどこかに保存され、後でそこから呼び出されます。

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

またはあなたはそれを事前ES6の方法をしなければならない場合は、あなたが前にthisを維持する必要があります:

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

大きな答え - またはプレES6 ".then(this.method2.bind(本))" –

+0

I用いる '.then(データ=> this.method(データ)) ' – Albert

0

一方向性関数がコンテキストを取得する(this)のは、呼び出されたオブジェクトからのものです(method1が正しいコンテキストを持っています - これはthisで呼び出されます)。関数自体への参照をthenに渡しています。あなたはthenの実装は次のようになりますことを想像することができます

function then(callback) { 

    // assume 'value' is the recently-fulfilled promise value 
    callback(value); 
} 

その例でcallbackは、あなたの関数への参照です。文脈はありません。既に指摘したように、関数を渡す前に、その関数をコンテキストにバインドすることで回避することができます。

15

あなたがthisを保存したい場合は、このようにそれを行う必要がありますプロミスハンドラは、デフォルトでグローバルオブジェクト(window)のコンテキストで呼び出されます。厳密モード(use strict;)の場合、コンテキストはundefinedです。これはmethod2method3に起こります。

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

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

method1について、あなたはthis.method1()としてmethod1を呼んでいます。これを呼び出すこの方法は、インスタンスであるthisオブジェクトのコンテキストで呼び出します。そのため、method1内のコンテキストがインスタンスになります。

+0

私は狂っていた!!!!私はあなたの答えを見たまで、ありがとう! –

2

基本的には、コンテキスト参照なしの関数参照を渡しています。

  1. 暗黙のうちに、thisのコンテキストが決定されます。グローバル関数またはバインディングなしの関数を呼び出すと、グローバルコンテキストとみなされます。*
  2. 直接参照による。 myObj.f()に電話するとmyObjthisとなります。**
  3. 手動バインドこれは、.bind.applyのような関数のクラスです。これらは、コンテキストが何であるかを明示的に示します。これらは常に前の2つよりも優先されます。あなたの例では

それの呼び出しで、グローバル関数や文脈ないものであることを暗示していますので、あなたは、関数参照を渡しています。 .bindを使用すると、thisが明示的に設定された新しい関数を作成することでこれを解決します。

*これは非完全モードでのみ該当します。厳密モードでは、thisundefinedに設定されます。

**使用している機能が手動でバインドされていないと仮定します。

関連する問題