2016-06-30 11 views
5

これは(以下)で「最大呼び出しスタックサイズを超えました」というエラーが発生しました。これは、 "this.actions"オブジェクト内で "this"が解釈されているためです。そのオブジェクト内で、 "this"はそのオブジェクト、またはUnitクラスのインスタンスを参照していますか?前者が.bind(this)を "this.actions"オブジェクトの最後に置くと、 "this"はクラスインスタンスを参照するようになります。もしそうなら、なぜですか?そうでない場合は、どうしてですか?オブジェクト内の "this"の範囲

function Unit(){ 
    this.move = function(direction){ 
    switch(direction){ 
     case 'up': { console.log('foo'); break; } 
     case 'down': { console.log('foooo'); break; } 
    } 
    console.log('bar'); 
    } 
    this.shoot = function(){console.log('zap')} 

    this.actions = { 
    'moveUp' : function(){ this.move('up') }, 
    'moveDown' : function(){ this.move('down') }, 
    'shoot' : function(){ this.shoot() } 
    } 

    return this 
} 
+0

あなたはオブジェクトのメソッドに 'move'をしてはいけません。より簡単に関数を作り、それを '' moveUp 'と呼んでください:move.call(this、' up ')}、 '' shoot'と同じ –

+0

有望です。答えに展開しますか? – DJG

答えて

2

actionsオブジェクト内のキーワードthisactionsオブジェクトを参照します。

いくつかの可能な修正は次のようになります。

function Unit(){ 
    var self = this; 
    this.move = function(direction){ 
    switch(direction){ 
     case 'up': { console.log('foo'); break; } 
     case 'down': { console.log('foooo'); break; } 
    } 
    console.log('bar'); 
    } 
    this.shoot = function(){console.log('zap')} 

    this.actions = { 
    'moveUp' : function(){ this.move('up') }.bind(self), 
    'moveDown' : function(){ this.move('down') }.bind(self), 
    'shoot' : function(){ this.shoot() }.bind(self) 
    } 

    return this 
} 

それとも、あなたはそれらのメソッドを呼び出すとき、あなたはcallまたはapply

などを使用することができます。

コンテキストで thisを理解
var coolUnit = new Unit(); 
Unit.actions.moveUp.call(coolUnit); 

をオブジェクトのいくつかの作業が必要ですが、ここにいくつかのリソースがあります:

How does the "this" keyword work?

http://unschooled.org/2012/03/understanding-javascript-this/

http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/

TL; DR - あなたはthisは、指定されたコンテキストであるかを追跡するために使用できる精神的な "ルール" のシリーズがあります。例えば。 ドット左のルールでは、 "ドット"の左側のオブジェクトがthisバインディングになります。上記の「ルール」を使用して

Object.foo() <- `this` in the method `foo` will point to `Object` 

、あなたはnew Unit.actions.moveUp()thisはアクションがその左の-ドットため、オブジェクトを指すように設定結合なければならないこと合理化することができます。

call/bind/applyを使用すると、thisを上記のようなコンテキストにバインドできます。

2

使用バインド

理由:

が言うことができます:

するvar R =新ユニット();

r.actions.moveup()を呼び出すと、moveup関数で渡された 'this'がactionsです。

function Unit(){ 
    this.move = function(direction){ 
    switch(direction){ 
     case 'up': { console.log('foo'); break; } 
     case 'down': { console.log('foooo'); break; } 
    } 
    console.log('bar'); 
    } 
    this.shoot = function(){console.log('zap')} 

    this.actions = { 
    'moveUp' : function(){ this.move('up') }.bind(this), 
    'moveDown' : function(){ this.move('down') }.bind(this), 
    'shoot' : function(){ this.shoot() }.bind(this) 
    } 

    return this 
} 
+1

stilが 'this.move'を使用している場合は、 ' 'moveUp':this.move.bind(this、 'up'); ' –

+0

と呼ぶ方が良いでしょう。自体? – DJG

+0

いいえ - そうではありません。 'this'バインディングは、コンストラクタが呼び出されるときに、新しい' Unit'を指し示すように設定されます。そのため、 'actions' objのメソッドは、' this'バインディングを新しい 'Unit'を指す概念で設定します。あなたが私の答えを見るならば、私はそれをもっと明示的にするために 'self' varを渡します。 –

0

最近、私はこのことについてthis articleを実行しました。

セクション4.2では、彼はあなたのコードに似た例を使用し、「新規」を忘れるという落とし穴を強調します。関数の呼び出しでは、グローバルオブジェクト(ウィンドウまたはブラウザ)を指すので、関数を返すときに関数をグローバルオブジェクトに置き、関数への参照を返します。新しいUnit()を使用してこれを返さない場合は、その上に関数を持つオブジェクトを取得します。

あなたはbindを使うことができますが、私はUnit.bind(Unit)のように奇妙に見えると思います。

あなたはまた、オブジェクトを返すために、工場の機能を使用することができ、あなたは、私が移動するための呼び出しからこれを削除

function Unit(){ 

    var move = function(direction){ 
    switch(direction){ 
     case 'up': { console.log('foo'); break; } 
     case 'down': { console.log('foooo'); break; } 
    } 
    console.log('bar'); 
    }; 
    var shoot = function(){console.log('zap')}; 

    var actions = { 
    moveUp : function(){ move('up') }, 
    moveDown : function(){ move('down') }, 
    shoot : shoot 
    }; 

return { 
    actions:actions 
}; 
} 

var player1=Unit(); 

player1.actions.shoot(); 
player1.actions.moveDown(); 
player1.actions.moveUp(); 

新しい忘れる心配する必要はありません、問題の一部は、アクションがされていますオブジェクトは関数ではないので、オブジェクト内の関数にbindを使用することができますが、コード内にあるように関数を閉じてから公開することができます。

また、self = thisを使用し、newキーワードを使用しない場合でも、ウィンドウ/ブラウザオブジェクトへの参照があり、グローバルスコープを作成しています。

+0

それでも動作しません。 – GingerPlusPlus

+0

編集して今すぐ動作します。なぜ私はこれがなぜ機能するかについてはっきりしていません。 – kingd9

1

もう1つの解決策:thisは変数ではありません。入れ子関数は "親"関数(Clousure)で定義されたすべての変数にアクセスできます - 変数を作成してthisを代入してthisの代わりに使用すれば、それはあなたが欲しいと期待することを行います:

function Unit(){ 
    var self = this; 
    self.move = function(direction){ 
    switch(direction){ 
     case 'up': { console.log('foo'); break; } 
     case 'down': { console.log('foooo'); break; } 
    } 
    console.log('bar'); 
    } 
    self.shoot = function(){console.log('zap')} 

    self.actions = { 
    'moveUp' : function(){ self.move('up') }, 
    'moveDown' : function(){ self.move('down') }, 
    'shoot' : function(){ self.shoot() } 
    } 

    return self 
} 
+0

なぜこれがベストプラクティスではないのですか? (それとも、私は分かりませんでしたか?) – DJG

関連する問題