11

Вопрос по prototype, websocket, callback, javascript – Javascript: прототипы с обратными вызовами и «это»

Я создаю класс на основе прототипаPerson это открывает соединение WebSocket и определяет функции обратного вызова как методы-прототипы.

Потому что внутри обратного вызоваthis будет ссылаться на объект WebSocket, я использовал другую переменную для удержанияPerson& APOS; sthis, Однако, когда я имею дело с несколькими экземплярами, переменная перезаписывается.

Вот небольшой отрывок, который показывает проблему:

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 создается, то при попытке отправить сообщение через сокет я получаю следующую ошибку:

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

Похоже, чтоself определяется глобально, и моя попытка получить ручку кPerson& APOS; sthis внутри обратного вызова не получается. Любые предложения о том, как этого добиться?

  • Error: User Rate Limit Exceeded;Error: User Rate Limit Exceeded

    от unexplored
  • Error: User Rate Limit Exceeded

    от
  • what's with all the missing semicolons to end each statementError: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от unexplored
  • @qwertymkvar делает его локальным для конструктора, что является еще одной проблемой

    от unexplored
  • Вы должны объявить этоvar во-первых, среди других вопросов

    от qwertymk
  • 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
        }
    }
    

  • 12

    Когда вы делаете: self = this

    Когда вы делаете:

    self = this
    

    Вы неявно создаете глобальную переменную, которая (поскольку она глобальная) будет иметь одинаковое значение для всех экземпляров. Локальные переменные, должны иметьvar, let или жеconst перед ними, как один из них:

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

    Но это не ваше решение здесь. Вы должны использоватьthis вместо. И, если вы собираетесь предоставить обратный вызов для веб-сокета, и вы хотите, чтобы человек, связанный с этим, рекомендовал вам просто поместить ссылку на объект 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
        }
    }
    

  • 5

    При объявлении переменных в Javascript, если вы не ставите

    var напротив, он будет рассматриваться как глобальная переменная, что вызывает некоторые проблемы в вашем случае.

    Пока конструктор ведет себя как положено, вы можете вместо этого сделать следующее, поэтомуname сохраняется в экземпляр Person, который вы создаете:

    // 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.

    // 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/