2012-04-04 20 views
10

He creado un prototipo basado en la clase Person que abre una conexión WebSocket y define las funciones de devolución de llamada como métodos prototipo.javascript: prototipos con devoluciones de llamada y 'esto'

Debido dentro de la devolución de llamada this se referirá al objeto WebSocket utilicé otra variable de aferrarse a la Person 's this. Sin embargo, cuando trato con varias instancias, la variable se sobrescribe.

Aquí está una pequeña cortada con tijeras que muestra el problema:

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  

Si se crea más de un Person, a continuación, al intentar enviar un mensaje a través del enchufe me sale el siguiente error:

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

Parece que self se define globalmente y mi intento de obtener un control Personthis dentro de la devolución de llamada falla. ¿Alguna sugerencia sobre cómo lograr eso?

+0

Es necesario para declarar que es un 'var' en primer lugar, entre otras cuestiones – qwertymk

+0

@qwertymk' var' hace que sea local para el constructor, que es otro problema – unexplored

Respuesta

10

Al hacer:

self = this 

Estás creando implícitamente una variable global que hace (ya que es mundial) se tener el mismo valor para todas las instancias. Las variables locales, deben tener var frente a ellos de esta manera:

var self = this; 

Pero, esa no es la solución aquí. Necesita en su lugar usar this. Y, si va a proporcionar una devolución de llamada para el websocket y desea a la persona asociada con eso, le sugiero que simplemente ponga una referencia al objeto Person en el websocket para que luego pueda recuperarlo desde allí. Y, ¿qué pasa con todos los puntos y comas faltantes para finalizar cada declaración? De todos modos, he aquí algo arreglado código:

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 Maldita sea, tan simple y estaba buscando no sé dónde encontrar soluciones extrañas. Por cierto, lo siento por ';'. Es mi primer proyecto de javascript y no entendí su importancia hasta que lo mencionaste y me hiciste leer acerca de ellos :) – unexplored

+0

'¿Qué pasa con todos los puntos y comas faltantes para finalizar cada afirmación? Estás tratando de imponer tus propios estilos de codificación. JavaSCRIPT es un lenguaje de scripting, y no debería preocuparse por esos estúpidos puntos y comas. Tal vez ha sido traumatizado por los lenguajes compilados como Java o C, pero la mayoría de los otros lenguajes de scripting no usan punto y coma (o muy raramente). Todos deberían tener la libertad de decidir usar o no punto y coma, pero ser consecuentes con las elecciones (y el OP). –

+2

@ CyrilDuchon-Doris - No tengo ningún interés en discutir esto contigo. Estoy interesado en codificar lo que considero buenos estilos de codificación sólidos y seguros incluso si el lenguaje no lo requiere y lo recomendaré en mis respuestas. Si quieres codificar de manera diferente o escribir respuestas de manera diferente, adelante, no te voy a detener, pero te recomendaré lo que creo que es un buen estilo. – jfriend00

0

self = this

Tu crear una variable global, es por eso que su código está roto.

también tratando de hacer referencia a self en el interior del prototipo no funciona, utilice 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

Soy consciente de que es mundial , Lo he mencionado en mi pregunta. Simplemente buscando formas correctas de hacerlo – unexplored

5

Cuando la declaración de variables en Javascript, si no se pone un var delante, que va a ser tratada como una variable global, lo que provoca algún problema en su caso .

Mientras que el constructor se comporta como se esperaba, es posible que desee hacer lo siguiente en su lugar, por lo name se guarda en la instancia de la persona que está creando:

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

Además, en WebSocket.onopen, ' esto 'cambia de la instancia de una Persona a la instancia de un WebSocket. Deberá conservar la 'Persona' para hacer referencia a ella dentro de 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); 
     }; 
    } 
}; 

Hope this helps!He aquí una jsFiddle para ir con ella: http://jsfiddle.net/WFdbe/

Cuestiones relacionadas