javascript:带有回调和“this”的原型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10014552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
javascript: prototypes with callbacks and 'this'
提问by unexplored
I've create a prototype based class Person
that opens a WebSocket connection and defines callback functions as prototype methods.
我创建了一个基于原型的类Person
,它打开一个 WebSocket 连接并将回调函数定义为原型方法。
Because inside the callback this
will refer to the WebSocket object I used another variable to hold on to the Person
's this
. However when I deal with multiple instances the variable gets overwritten.
因为里面的回调this
将引用的WebSocket对象我用另一个变量来保存到Person
的this
。但是,当我处理多个实例时,变量会被覆盖。
Here is a small snipped that shows the issue:
这是一个显示问题的小片段:
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
If more than one Person
is created, then when trying to send a message via the socket I get the following error:
如果Person
创建了多个,那么在尝试通过套接字发送消息时,我收到以下错误:
Uncaught Error: INVALID_STATE_ERR: DOM Exception 11
未捕获的错误:INVALID_STATE_ERR:DOM 异常 11
So it seems that self
is defined globally and my attempt to get a handle to the Person
's this
inside the callback fails. Any suggestions on how to achieve that?
所以它似乎self
是全局定义的,我试图在回调中获取Person
's的句柄this
失败。关于如何实现这一目标的任何建议?
回答by jfriend00
When you do:
当你这样做时:
self = this
You are implicitly creating a global variable which (since it's global) will have the same value for all instances. Local variables, must have var
, let
or const
in front of them like one of these:
您正在隐式地创建一个全局变量(因为它是全局的)对于所有实例都具有相同的值。局部变量,必须有var
,let
或const
在它们前面像以下之一:
var self = this;
const self = this;
let self = this;
But, that isn't your solution here. You need to be using this
instead. And, if you're going to supply a callback for the websocket and you want the person associated with that, I would suggest you just put a reference to the Person object on the websocket so you can then retrieve it from there. And, what's with all the missing semicolons to end each statement? Anyway, here is some fixed up code:
但是,这不是您的解决方案。您需要改为使用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
}
}
回答by DashK
When declaring variables in Javascript, if you don't put a var
in front, it'll be treated as a global variable, which causes some problem in your case.
在 Javascript 中声明变量时,如果您不将 avar
放在前面,它将被视为全局变量,这在您的情况下会导致一些问题。
While the constructor is behaving as expected, you may want to do the following instead, so name
is saved to the instance of Person you are creating:
当构造函数按预期运行时,您可能需要执行以下操作,因此name
将保存到您正在创建的 Person 实例中:
// Constructor
function Person(name){
// You don't need to reference "self" here. It's already implied.
this.name = name;
}
In addition, in WebSocket.onopen, 'this' changes from the instance of a Person to the instance of a WebSocket. You'll need to preserve the 'Person' in order to reference it inside WebSocket.onopen.
另外,在WebSocket.onopen中,'this'从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);
};
}
};
Hope this helps! Here's a JSFiddle to go with it: http://jsfiddle.net/WFdbe/
希望这可以帮助!这是一个与之配套的 JSFiddle:http: //jsfiddle.net/WFdbe/
回答by Raynos
self = this
self = this
Your creating a global variable, that's why your code is broken.
您创建了一个全局变量,这就是您的代码被破坏的原因。
Also trying to reference self
inside the prototype does not work, use 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
}
}