我创建了一个基于原型的类Person
,它打开一个WebSocket连接,并将回调函数定义为原型方法。
因为在回调this
内部将引用WebSocket对象,我使用另一个变量来保持Person
的{{1}}。但是当我处理多个实例时,变量会被覆盖。
这是一个显示问题的小剪片:
this
如果创建了多个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
,那么当尝试通过套接字发送消息时,我会收到以下错误:
未捕获错误:INVALID_STATE_ERR:DOM例外11
所以看起来Person
是全局定义的,我在回调中尝试获取self
的{{1}}的句柄失败了。关于如何实现这一目标的任何建议?
答案 0 :(得分:12)
当你这样做时:
self = this
您隐式创建一个全局变量(因为它是全局变量)将对所有实例具有相同的值。局部变量,前面必须有var
,let
或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
}
}
答案 1 :(得分: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中,“this”从Person的实例更改为WebSocket的实例。您需要保留“Person”才能在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/
答案 2 :(得分: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
}
}