11

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

コールバック内でthisは WebSocket オブジェクトが参照されるため、別の変数を使用しPersonthis. ただし、複数のインスタンスを処理すると、変数が上書きされます。

これは、問題を示す小さな抜粋です。

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    

複数Personのメッセージが作成された場合、ソケット経由でメッセージを送信しようとすると、次のエラーが発生します。

キャッチされないエラー: INVALID_STATE_ERR: DOM 例外 11

そのため、グローバルに定義されているようで、コールバック内の へのハンドルを取得しようとすると失敗しますself。それを達成する方法について何か提案はありますか?Personthis

4

3 に答える 3

13

あなたがするとき:

self = this

(グローバルであるため)すべてのインスタンスで同じ値を持つグローバル変数を暗黙的に作成しています。ローカル変数は、次のいずれかのようにvarletまたはconstその前にある必要があります。

var self = this;
const self = this;
let self = this;

しかし、それはここでのあなたの解決策ではありません。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
    }
}
于 2012-04-04T15:48:55.620 に答える
5

Javascriptで変数を宣言するとき、前にaを置かないvarと、グローバル変数として扱われ、問題が発生します。

コンストラクターが期待どおりに動作している間、代わりに次のことを実行したい場合があるため、name作成している Person のインスタンスに保存されます。

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

また、WebSocket.onopen では、「this」が 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); 
        };
    }
};

お役に立てれば!これに対応する JSFiddle は次のとおりです: http://jsfiddle.net/WFdbe/

于 2012-04-04T16:12:40.150 に答える
1

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
    }
}
于 2012-04-04T15:45:00.317 に答える