我是Javascript的新手,我刚刚发现了用于定义对象函数的属性关键字.我尝试使用对象重构我的websocket实验,但我无法让它工作.
这工作(没有对象):
var ws = new WebSocket(something, somethingelse);
ws.onopen = function() {
ws.send("hello");
console.log("works");
}
Run Code Online (Sandbox Code Playgroud)
但这不是:
function MyObject() {
this.ws = new WebSocket(something, somethingelse);
this.ws.onopen = this.onOpen;
}
MyObject.prototype.onOpen = function() {
this.ws.send("hello"); // undefined!
};
Run Code Online (Sandbox Code Playgroud)
为什么ws未定义?我是否错误地分配了onOpen功能?
您正确分配函数(只有一种分配函数的方法),您的问题是函数的上下文发生了变化.
考虑这一行:
this.ws.onopen = this.onOpen;
Run Code Online (Sandbox Code Playgroud)
可能性1:
现在我假设,在 WebSocket某个地方,这个函数被调用作为对开放连接(如事件处理程序)的响应,可能就像
this.onopen();
Run Code Online (Sandbox Code Playgroud)
什么this是指内部的功能是通过确定如何调用一个函数在运行时(<-读此链接,它帮助了很多).它在定义时间不受约束.在您的情况下,this将引用WebSocket实例.
所以,如果里面所谓的这种方式,内MyObject.prototype.onOpen,this指this.ws的WebSocket实例,它不具有ws产权,而不是MyObject实例.
这可以通过两种方式解决:
既然this已经提到this.ws,你可以send直接打电话this:
MyObject.prototype.onOpen = function() {
this.send("hello");
};
Run Code Online (Sandbox Code Playgroud)如果你希望thisinside MyObject.prototype.onOpen总是引用MyObject实例,你必须保持对实例的显式引用,例如通过闭包:
var self = this;
this.ws.onopen = function() {
self.onOpen();
};
Run Code Online (Sandbox Code Playgroud)
现在在里面onOpen,this指的是MyObject具有属性的实例ws,就像你在构造函数中设置它一样.
在支持ECMAScript 5的浏览器中,函数已经有了这种技术的方法,称为.bind():
this.ws.onopen = this.onOpen.bind(this);
Run Code Online (Sandbox Code Playgroud)可能性2:
它也可能以这种方式WebSocket调用onopen:
this.onopen.call(null);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,this将引用window或将来undefined,取决于代码是否以严格模式运行(无关紧要,无论如何都是一个问题).
这种情况只能通过第一种可能性的第二种解决方案来解决.
为什么第一个例子有效?
var ws = new WebSocket(something, somethingelse);
ws.onopen = function() {
ws.send("hello");
console.log("works");
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您指定的函数ws.onopen是一个闭包,也关闭此范围中定义的变量ws.在这个意义上,它类似于解决问题的第二种方式,但是
ws.onopen = function() {
this.send("hello");
console.log("works");
}
Run Code Online (Sandbox Code Playgroud)
可能也会奏效.
| 归档时间: |
|
| 查看次数: |
395 次 |
| 最近记录: |