如何在javascript中分配函数?

时间:2012-04-16 14:17:09

标签: javascript

我是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功能?

1 个答案:

答案 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.wsWebSocket实例,它没有ws属性,而不是MyObject实例。

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

  1. 由于this已引用this.ws,您可以直接在send上致电this

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

  3. 可能性2:

    也可能WebSocket以这种方式调用onopen

    this.onopen.call(null);
    

    在这种情况下,this会引用windowundefined,具体取决于代码是否以严格模式运行(无论如何都无关紧要)这是一个问题)。

    这种情况只能通过第一种可能性的第二种解决方案来解决。


    为什么第一个示例有效?

    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");
    }
    

    也可能会有效。