2012-04-04 10 views
10

WebSocket接続を開き、プロトタイプメソッドとしてコールバック関数を定義するプロトタイプベースのクラスPersonを作成しました。javacript:コールバック付きプロトタイプと 'this'

thisはWebSocketオブジェクトを参照するため、別の変数を使用してPersonthisを保持しています。しかし、私が複数のインスタンスを扱うとき、変数は上書きされます。ここで

が問題を示して小さなスニップです:複数のPersonが作成されている場合は

function Person(name){ 
    self = this 
    self.name = name 
} 

Person.prototype = { 
    getName : function(){ 
     return self.name 
    }, 

    openConnection : function(host, port){ 
     self.pointCount = 0 
     self.ws = new WebSocket("ws://" + host + ":" + port) 
     self.ws.onopen = self.onOpenConnection 
    }, 

    onOpenConnection : function() { 
     console.log(this) // prints the websocket 
     console.log(self) // prints the person 
     self.ws.send(self.name) // works only if one person exists 
    } 
} 

var p1 = new Person("Jonh") 
var p2 = new Person("Adam") 

console.log(p1.getName()) // Prints Adam 
console.log(p2.getName()) // Prints Adam 

p1.openConnection("localhost", 7000) // opens connection for p1 
p2.openConnection("localhost", 7000) // opens another connection for p1  

ソケット経由でメッセージを送信しようとしたときに、私は次のエラーを取得する:

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

したがって、selfがグローバルに定義されており、コールバック内でPersonthisへのハンドルを取得しようとすると失敗します。どのようにそれを達成するための任意の提案?

+0

他の問題のなかで、最初に「var」と宣言する必要があります – qwertymk

+0

@qwertymk 'var'は別の問題であるコンストラクタに対してローカルになります – unexplored

答えて

10

を使用します。

self = this 

あなたは暗黙的に(それはグローバルなので)、グローバル変数をします作成していますすべてのインスタンスに対して同じ値を持ちます。それがここにあなたのソリューションではありません、

var self = this; 

しかし:ローカル変数は、このような彼らの前にvarを持っている必要があります。代わりにthisを使用する必要があります。そして、もしあなたがwebsocketのコールバックを提供し、それに関連付けられた人を望むなら、WebsocketにPersonオブジェクトへの参照を渡してそこから取得できるようにすることをお勧めします。そして、各ステートメントを終了するために、すべてのセミコロンが欠けていますか?とにかく、ここでいくつかのアップ固定コードです:

function Person(name){ 
    this.name = name; 
} 

Person.prototype = { 
    getName : function(){ 
     return this.name; 
    }, 

    openConnection : function(host, port){ 
     this.pointCount = 0; 
     this.ws = new WebSocket("ws://" + host + ":" + port); 
     // save person reference on the web socket 
     // so we have access to the person from web socket callbacks 
     this.ws.person = this; 
     this.ws.onopen = this.onOpenConnection; 
    }, 

    onOpenConnection : function() { 
     // "this" will be the websocket 
     // "this.person" is the person object 
     console.log(this); // prints the websocket 
     console.log(this.person); // prints the person 
     this.send(this.person.name); // works only if one person exists 
    } 
} 
+0

+1すごくシンプルで、私は奇妙なソリューションのためのどこを知りませんでした探していた。ところで、ごめんなさい。それは私の最初のjavascriptプロジェクトであり、あなたがそれを言及し、それらについて私に読ませてくれるまで、彼らの重要性をかなり理解していませんでした:) – unexplored

+0

'それぞれのステートメントを終わらせるセミコロンがありません'あなたは独自のコーディングスタイルを課そうとしています。 JavaSCRIPTはスクリプト言語であり、あなたはそれらのばかげたセミコロンについて心配する必要はありません。おそらく、あなたはJavaやCのようなコンパイルされた言語で傷ついているかもしれませんが、ほとんどのスクリプト言語はセミコロンを使用していません。セミコロンを使用するかどうかは自由に決めることができますが、選択肢については一貫していなければなりません(OPも)。 –

+2

@ CyrilDuchon-Doris - 私はあなたと議論することに興味がありません。私は、言語がそれを必要としなくても、良いソリッドで安全なコーディングスタイルと考えているものをコーディングすることに興味があり、私はそれを私の答えにお勧めします。あなたが違った方法でコードを書いたり、答えを別々に書いたりしたいのなら、私はあなたを止めるつもりはありませんが、私は良いスタイルだと思います。 – jfriend00

0

self = this

あなたは、グローバル変数を作成し、あなたのコードが壊れている理由、それはです。

また、プロトタイプの内側selfを参照しようとすると、動作しない、あなたが行うとthis

function Person(name){ 
    this.name = name 
} 

Person.prototype = { 
    openConnection : function(host, port){ 
     this.pointCount = 0 
     this.ws = new WebSocket("ws://" + host + ":" + port) 
     this.ws.onopen = this.onOpenConnection.bind(this) 
    }, 
    constructor: Person,  
    onOpenConnection : function() { 
     console.log(this) // prints the person 
     this.ws.send(this.name) // works only if one person exists 
    } 
} 
+0

私はそれがグローバルであることを認識しています私は私の質問でそれを言いました。ちょうどそれを行う正しい方法を探して – unexplored

5

あなたが前にvarを入れていない場合は、JavaScriptで変数を宣言すると、それはあなたのケースでいくつかの問題が発生するグローバル変数として扱われます。

コンストラクタは予想通り、あなたの代わりに次の操作を実行したい場合があり動作しているが、そうnameを作成している人のインスタンスに保存されます: '、また

// Constructor 
function Person(name){ 
    // You don't need to reference "self" here. It's already implied. 
    this.name = name; 
} 

を、WebSocket.onopenにこれはPersonのインスタンスからWebSocketのインスタンスに変更されます。あなたはWebSocket.onopenの中でそれを参照するために 'Person'を保持する必要があります。

// Prototype 
Person.prototype = { 
    getName : function(){ 
     // 'this' in this case refers to an instance of Person. 
     // So, when creating John, this.name will be John. 
     return this.name; 
    }, 

    openConnection : function(host, port) { 
     // Similar to getName(...), this refers to an instance of Person. 
     // In your example, this.pointCount is NOT shared between John and Adam 
     this.pointCount = 0; 
     this.ws = new WebSocket("ws://" + host + (port ? ':' + port : '')); 

     // In WebSocket.onopen below, you're working with a new scope, so you 
     // won't have access to 'this' as the Person anymore. You need to save 
     // 'this' somewhere, so you can reference it in the new scope. 
     // ***** 
     var self = this; 

     this.ws.onopen = function() { 
      // In this function, a new scope has been created. 'this' no 
      // longer refers to John/Adam (The instance of Person), but to 
      // WebSocket instead. 

      console.log(this); // 'this' references the WebSocket instance 
      console.log(self); // 'self' references the 'self' in the outer 
           // scope. See ***** 

      // Since this = WebSocket in this scope, all we need to do 
      // is this.send(...). If you'd like to obtain the refer 
      // to the instance of the Person you worked with, you can 
      // use the 'self' variable 
      this.send(self.name); 
     }; 
    } 
}; 

これが役に立ちます。http://jsfiddle.net/WFdbe/

関連する問題