如何在javascript中分配函数?

wan*_*ist 1 javascript

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

Fel*_*ing 6

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

考虑这一行:

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,thisthis.wsWebSocket实例,它不具有ws产权,而不是MyObject实例.

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

  1. 既然this已经提到this.ws,你可以send直接打电话this:

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

可能也会奏效.