javascript:带回调的原型和'this'

une*_*red 11 javascript prototype callback websocket

我创建了一个基于原型的类Person,它打开一个WebSocket连接,并将回调函数定义为原型方法.

因为里面的回调this将引用的WebSocket对象我用另一个变量来保存到Personthis.但是当我处理多个实例时,变量会被覆盖.

这是一个小剪片,显示了这个问题:

function Person(name){
    self = this
    self.name = name
}

Person.prototype = {
    getName : function(){
        return self.name
    },

    openConnection : function(host, port){
        self.pointCount = 0
        self.ws = new WebSocket("ws://" + host + ":" + port)
        self.ws.onopen = self.onOpenConnection
    },

    onOpenConnection : function()   {
        console.log(this) // prints the websocket
        console.log(self) // prints the person
        self.ws.send(self.name) // works only if one person exists
    }
}

var p1 = new Person("Jonh")
var p2 = new Person("Adam")

console.log(p1.getName()) // Prints Adam
console.log(p2.getName()) // Prints Adam

p1.openConnection("localhost", 7000) // opens connection for p1
p2.openConnection("localhost", 7000) // opens another connection for p1    
Run Code Online (Sandbox Code Playgroud)

如果Person创建了多个,那么当尝试通过套接字发送消息时,我收到以下错误:

未捕获错误:INVALID_STATE_ERR:DOM异常11

如此看来,self是全局定义和我试图让一个句柄Personthis内部回调失败.关于如何实现这一点的任何建议?

jfr*_*d00 13

当你这样做时:

self = this
Run Code Online (Sandbox Code Playgroud)

您隐式创建一个全局变量(因为它是全局的)将对所有实例具有相同的值.局部变量,必须具备var,letconst在他们面前喜欢其中之一:

var self = this;
const self = this;
let self = this;
Run Code Online (Sandbox Code Playgroud)

但是,这不是你的解决方案.你需要改为使用this.并且,如果您要为websocket提供回调并且您想要与之关联的人,我建议您只在websocket上添加对Person对象的引用,以便您可以从那里检索它.并且,所有缺少的分号结束每个语句是什么?无论如何,这里有一些固定的代码:

function Person(name){
    this.name = name;
}

Person.prototype = {
    getName : function(){
        return this.name;
    },

    openConnection : function(host, port){
        this.pointCount = 0;
        this.ws = new WebSocket("ws://" + host + ":" + port);
        // save person reference on the web socket
        // so we have access to the person from web socket callbacks
        this.ws.person = this;   
        this.ws.onopen = this.onOpenConnection;
    },

    onOpenConnection : function()   {
        // "this" will be the websocket
        // "this.person" is the person object
        console.log(this); // prints the websocket
        console.log(this.person); // prints the person
        this.send(this.person.name); // works only if one person exists
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @ CyrilDuchon-Doris - 我没有兴趣和你争论这件事.即使语言不需要,我也有兴趣编写我认为好的实用且安全的编码样式的代码,我将在我的答案中推荐.如果你想以不同的方式编写代码或者以不同的方式写答案,那么我就不会阻止你,但我会推荐一些我认为好的风格. (2认同)

Das*_*shK 5

在Javascript中声明变量时,如果你没有放在var前面,它将被视为一个全局变量,这会导致你的情况出现一些问题.

虽然构造函数的行为符合预期,但您可能希望执行以下操作,因此name将其保存到您正在创建的Person实例中:

// Constructor
function Person(name){
    // You don't need to reference "self" here. It's already implied.
    this.name = name;
}
Run Code Online (Sandbox Code Playgroud)

另外,在WebSocket.onopen中,'this'从Person的实例变为WebSocket的实例.您需要保留"Person"才能在WebSocket.onopen中引用它.

// Prototype
Person.prototype = {
    getName : function(){
        // 'this' in this case refers to an instance of Person. 
        // So, when creating John, this.name will be John. 
        return this.name;
    },

    openConnection : function(host, port) {
        // Similar to getName(...), this refers to an instance of Person.
        // In your example, this.pointCount is NOT shared between John and Adam
        this.pointCount = 0;
        this.ws = new WebSocket("ws://" + host + (port ? ':' + port : ''));

        // In WebSocket.onopen below, you're working with a new scope, so you 
        // won't have access to 'this' as the Person anymore. You need to save 
        // 'this' somewhere, so you can reference it in the new scope.
        // *****
        var self = this;   

        this.ws.onopen = function() {
            // In this function, a new scope has been created. 'this' no 
            // longer refers to John/Adam (The instance of Person), but to 
            // WebSocket instead.

            console.log(this); // 'this' references the WebSocket instance
            console.log(self); // 'self' references the 'self' in the outer 
                               // scope. See *****

            // Since this = WebSocket in this scope, all we need to do
            // is this.send(...). If you'd like to obtain the refer
            // to the instance of the Person you worked with, you can
            // use the 'self' variable
            this.send(self.name); 
        };
    }
};
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!这是一个JSFiddle:http://jsfiddle.net/WFdbe/