2016-07-22 8 views
0

コード例:prototype.objectで 'this'コンテキストを正しくバインドする方法はありますか?

function Test() { 
    this.name = 'test' 
} 

Test.prototype.normal = function() { 
    console.log('normal', this.name); 
}; 

Test.prototype.special = { 
    name: 'special', 
    start: function() { 
     console.log("special", this.name); 
    } 
} 

test = new Test; 

test.normal(); // Response 'normal, test' 

test.special.start(); // Response 'special, special' 

に私はどのように私はこれを達成することができます「特別な、テスト」

をログに記録するspecial.start機能が欲しいですか?私はcoffeescriptを使用しているので、コーヒーの例が分かりますが、javascriptの例も同様に動作します!前もって感謝します!

+0

あなたは実際にここで何を達成しようとしていますか?そして、関数の通常の 'this'は、関数Testにスコープされていません。 'special.start'はプロトタイプにスコープされていません。 'this'値はすべての呼び出しでJavaScriptランタイムによって動的に設定されます。 –

+0

ああ、情報ありがとうございました – Dex

+0

'Test.prototype.special.start = Test.prototype.special.start.bind(this);' - ただ** no **。プロトタイプを再バインドしています。これは、すべての単一インスタンスに影響します。 'test2 = new Test'と' test3 = new Test'を追加すると、本当に混乱する結果になります。 – deceze

答えて

2
  1. の値を持つ新しい関数を作成することができますは、の呼び出し時間に、関数の呼び出し方法によって決定されます。
  2. (インスタンス)にバインドする場合は、Test(コンストラクタ関数)ではなくバインドします。

あなたは、特定のコール時の調整を行う代わりに、インスタンスを持って前に明らかに起こることができないtestインスタンスに機能を、事前に結合し、そしてそれが個別に各インスタンスのために行われる必要がありますしたくない場合。したがって、これに対する唯一の解決策は次のとおりです。

function Test() { 
    this.special = { 
     start: (function() { ... }).bind(this) 
    }; 
} 

おそらく、あなたの代わりに、インラインのプロトタイプに関数を定義することをお勧めします。しかし、あなたはまだ、コンストラクタでそれをバインドする必要があります:

function Test() { 
    this.special = { 
     start: this._start.bind(this) 
    }; 
} 

Test.prototype._start = function() { ... }; 
1

あなたの質問は、この引数についての関数であると思います。私はその後、myMethod内部このキーワードは、変数objを参照するobj.myMethodのようなメソッドを呼び出した場合、適用するか、呼び出し方法

test = function(){ this.name = 'test'; } 
 

 
test.prototype.special = { name:'special', start : function(){alert(this.name)} } 
 

 
var t = new test(); 
 

 
t.special.start.call(t); 
 

 
t.special.start();
JavaScriptで

を使用してみてください。 apply, callbindを使用して、 thisキーワードの値を myMethodに変更することができます。代わりに、どこでもコールを使用しての

、我々はbind

test = function(){ this.name = 'test'; } 
 

 
test.prototype.special = { name:'special', start : function(){alert(this.name)} } 
 

 
var t = new test(); 
 

 
//t.start and t.special.start are now different functions as per MDN 
 
t.start = t.special.start.bind(t); 
 

 
t.start(); 
 

 
t.special.start();

Call

Apply

+0

Thx Kira!しかし、今私は常に電話をかけたり、応募したりする必要があります。私はこれを事前バインドできませんか? – Dex

+0

@Dex 'prototype'の変数はすべてのインスタンスで共有されます。関数をあるインスタンスにバインドすると、他のインスタンスの 'this'バインディングが破損します。おそらく、あなたは 'prototype'を使うべきではありません。 – 4castle

+0

@ ZombieChowder可能であれば、リンクに属性を付けることが望ましいです。 – 4castle

0

はすでにキラの答えのコメントに基づいて現在の回答に追加するには、スコープがどのように動作するかの基本的な誤解があるようです。 Javascriptはレキシカルスコープを持っています。スコープはソースコードの構造によって定義されますが、1つの例外はthisです。 thisは動的スコープであり、スコープは呼び出し元によって定義されます。コード内:

bar = 3 
test = (foo) -> 
    foo + bar # bar can be seen, because its in an outer scope test can see 

これまでのところとても良い。

class Test 
    constructor: (@foo) -> 
    getFoo: -> @foo 

getFoo部分がTest.prototype.getFoo = function...と同等です:今、クラスを定義することができます。 this(@)のスコープはgetFooです。 getFoo呼び出しthisを決定します。

obj1 = new Test 2 
obj1.getFoo() # 2 

fn = Test.prototype.getFoo; 
fn() 

fn今の代わりobj1の方法のスタンドアローン機能です。 fnと呼ぶと、2つのうちの1つが起こります。厳密なモードでは、エラーが発生します。グローバルコンテキストで呼び出すので、thisgetFooは定義されていません。非厳密では、それはグローバルwindowになり、おそらくそこにないfooプロパティを探します。

私たちすることができますbindcall、またはapply経由this値。

obj2 = 
    foo: 3 

Test.prototype.getFoo.call(obj) # 3 

ここでは、これを使ってTestクラスのメソッドを借用しています。だからバインドはどこに来ますか?

class Test 
    constructor: (@foo) -> 
    @clickHandler = Test.prototype.clickHandler.bind this 

    clickHandler: (e) -> 
    console.log @foo 

我々はthisコンテキストが蒸発する.addEventListenerにメソッドを渡すことになりますので、意味我々:私たちのクラスは、イベントハンドラのように、我々はが異なるコンテキストで使用されます知っている方法を持っていることを言うことができますそれをコンストラクタで行う各インスタンスにバインドする必要があります。

+0

あなたのawnser、ありがとう、私は今EDIT2で書かれている今有効ですか? – Dex

+0

@Dexは有効ですが、実際に* do *するケースはまれです。私はイベントハンドラの例を使用しましたが、 'setTimeout'も正当なユースケースになります。基本的には、オブジェクトメソッドを高次関数(別の関数への関数の引数)として使用する場合にのみこれを行います。 –

関連する問題