我是Javascript的新手,我刚刚发现了用于定义对象函数的属性关键字。我尝试使用对象重构我的websocket实验,但我无法让它工作。
这有效(没有对象):
var ws = new WebSocket(something, somethingelse);
ws.onopen = function() {
ws.send("hello");
console.log("works");
}
但这不是:
function MyObject() {
this.ws = new WebSocket(something, somethingelse);
this.ws.onopen = this.onOpen;
}
MyObject.prototype.onOpen = function() {
this.ws.send("hello"); // undefined!
};
为什么ws未定义?我是否错误地分配了onOpen功能?
答案 0 :(得分:6)
您正在正确分配函数(只有一种分配函数的方法),您的问题是函数的上下文发生了变化。
考虑这一行:
this.ws.onopen = this.onOpen;
可能性1:
现在我假设在 WebSocket
内,某处此函数被调用作为对开放连接的响应(如事件处理程序),可能就像
this.onopen();
What this
refers to inside a function is determined by how a function is called on run time(<-
阅读此链接,它有很多帮助)。它在定义时间不受约束。在您的情况下,this
会引用WebSocket
实例。
因此,如果以这种方式调用,在MyObject.prototype.onOpen
内,this
引用this.ws
,WebSocket
实例,它没有ws
属性,而不是MyObject
实例。
这可以通过两种方式解决:
由于this
已引用this.ws
,您可以直接在send
上致电this
:
MyObject.prototype.onOpen = function() {
this.send("hello");
};
如果您希望this
内的MyObject.prototype.onOpen
始终引用MyObject
实例,则必须明确引用该实例,例如通过关闭:
var self = this;
this.ws.onopen = function() {
self.onOpen();
};
现在在onOpen
内,this
指的是MyObject
实例,它具有属性ws
,就像您在构造函数中设置它一样。
在支持ECMAScript 5的浏览器中,函数已经有了这种技术的方法,称为.bind()
:
this.ws.onopen = this.onOpen.bind(this);
可能性2:
也可能WebSocket
以这种方式调用onopen
:
this.onopen.call(null);
在这种情况下,this
会引用window
或undefined
,具体取决于代码是否以严格模式运行(无论如何都无关紧要)这是一个问题)。
这种情况只能通过第一种可能性的第二种解决方案来解决。
为什么第一个示例有效?
var ws = new WebSocket(something, somethingelse);
ws.onopen = function() {
ws.send("hello");
console.log("works");
}
在这种情况下,您分配给ws.onopen
的函数是一个闭包,关闭此范围中定义的变量,也是ws
。在这个意义上,它类似于解决问题的第二种方式,但
ws.onopen = function() {
this.send("hello");
console.log("works");
}
也可能会有效。