2012-04-04 41 views
10

Stworzyłem opartą na prototypach klasę Person, która otwiera połączenie WebSocket i definiuje funkcje oddzwaniania jako metody prototypowe.javascript: prototypy z wywołaniami zwrotnymi i "tym"

Ponieważ wewnątrz wywołania zwrotnego this będzie odnosić się do obiektu WebSocket użyłem innej zmiennej do utrzymania Person 's this. Jednak gdy zajmuję się wieloma instancjami, zmienna zostaje nadpisana.

Oto mały snipped który pokazuje problem:

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  

Jeśli więcej niż jeden Person jest tworzona, a następnie, gdy próbuje wysłać wiadomość za pośrednictwem gniazda pojawia się następujący błąd:

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

Wygląda na to, że self jest zdefiniowany globalnie i moja próba uzyskania dojścia do Person 's this wewnątrz funkcji zwrotnej kończy się niepowodzeniem. Wszelkie sugestie, jak to osiągnąć?

+0

trzeba deklarować, że jest to 'var' pierwsze, wśród innych zagadnień – qwertymk

+0

@qwertymk' var' sprawia, że ​​lokalne do konstruktora, który jest inny problem – unexplored

Odpowiedz

10

Kiedy zrobić:

self = this 

Jesteś niejawnie tworząc zmienną globalną, która (ponieważ jest to globalna) będzie mają tę samą wartość dla wszystkich instancji. zmienne lokalne, musi mieć var przed nimi tak:

var self = this; 

jednak, że nie jest to rozwiązanie tutaj. Musisz zamiast tego używać this. Jeśli masz zamiar dostarczyć wywołanie zwrotne dla websocket i chcesz, aby osoba była z nim powiązana, proponuję po prostu umieścić odnośnik do obiektu Person na websocket, abyś mógł go pobrać. A co z wszystkimi brakującymi średnikami, aby zakończyć każde stwierdzenie? W każdym razie, tu jest jakiś stały się kod:

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 Cholera, tak prosty i szukałem nie wiem, gdzie dla dziwnych rozwiązań. BTW przykro mi z powodu ';'. To jest mój pierwszy projekt javascript i nie bardzo rozumiałem ich znaczenie, dopóki o nim nie wspomniałeś i nie przeczytałem o nich :) – unexplored

+0

'co z wszystkimi brakującymi średnikami, aby zakończyć każde stwierdzenie' Próbujesz narzucić własne style kodowania. JavaSCRIPT jest językiem skryptowym i nie powinieneś się martwić o te głupie średniki. Być może doświadczyłeś traumy w skompilowanych językach, takich jak Java lub C, ale większość innych języków skryptowych nie używa średników (lub bardzo rzadko). Każdy powinien mieć swobodę decydowania o użyciu średników, a nie być konsekwentnym w kwestii wyborów (i OP był). –

+2

@ CyrilDuchon-Doris - Nie jestem zainteresowany kłóceniem się z tobą. Interesuje mnie kodowanie tego, co uważam za dobre, solidne i bezpieczne style kodowania, nawet jeśli język tego nie wymaga, a ja polecę to w moich odpowiedziach. Jeśli chcesz kodować inaczej lub pisać odpowiedzi inaczej idź przed siebie, nie zatrzymuję cię, ale polecę to, co uważam za dobry styl. – jfriend00

0

self = this

Twój tworząc zmienną globalną, dlatego kod jest zepsuty.

próbuje także odwołać self wewnątrz prototypu nie działa, użyj 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

Zdaję sobie sprawę, że jest to globalne Wspomniałem o tym w moim pytaniu. Po prostu szukam poprawnych sposobów robienia tego. – unexplored

5

Podczas deklarowania zmiennych w JavaScript, jeśli nie umieścić var z przodu, to będzie traktowany jako zmienną globalną, co powoduje pewne problemy w przypadku .

Podczas gdy konstruktor zachowuje się zgodnie z oczekiwaniami, można wykonać następujące czynności zamiast, tak name zostanie zapisany na przykład osoby tworzysz:

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

Ponadto w WebSocket.onopen " to "zmienia się z instancji osoby na instancję WebSocket. Konieczne będzie zachowanie "Osoby" w celu odniesienia się do niej w 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); 
     }; 
    } 
}; 

Mam nadzieję, że to pomoże!Oto JSFiddle iść z nim: http://jsfiddle.net/WFdbe/

Powiązane problemy