1

我是 Javascript 新手,我刚刚发现了用于定义对象函数的 property 关键字。我尝试使用对象重构我的 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 函数?

4

1 回答 1

6

您正在正确分配函数(只有一种分配函数的方法),您的问题是函数的上下文发生了变化。

考虑这一行:

this.ws.onopen = this.onOpen;

可能性一:

现在我假设, WebSocket某个地方,这个函数被调用作为对打开连接(如事件处理程序)的响应,可能像

this.onopen();

this函数内部所指的内容取决于函数在运行时的调用方式<-阅读此链接,它有很大帮助)。它在定义时不受约束。在您的情况下,this将引用该WebSocket实例。

所以 inside 如果以这种方式调用, insideMyObject.prototype.onOpenthis的是没有属性的实例,而不是this.ws实例。WebSocketwsMyObject

这可以通过两种方式解决:

  1. 既然this已经引用了this.ws,可以send直接调用this

    MyObject.prototype.onOpen = function() {
        this.send("hello");
    };
    
  2. 如果您希望thisinsideMyObject.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");
}

可能也会起作用。

于 2012-04-16T14:22:53.757 回答