javascript:带有回调和“this”的原型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10014552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 08:28:16  来源:igfitidea点击:

javascript: prototypes with callbacks and 'this'

javascriptcallbackwebsocketprototype

提问by unexplored

I've create a prototype based class Personthat opens a WebSocket connection and defines callback functions as prototype methods.

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

Because inside the callback thiswill refer to the WebSocket object I used another variable to hold on to the Person's this. However when I deal with multiple instances the variable gets overwritten.

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

Here is a small snipped that shows the issue:

这是一个显示问题的小片段:

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    

If more than one Personis created, then when trying to send a message via the socket I get the following error:

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

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

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

So it seems that selfis defined globally and my attempt to get a handle to the Person's thisinside the callback fails. Any suggestions on how to achieve that?

所以它似乎self是全局定义的,我试图在回调中获取Person's的句柄this失败。关于如何实现这一目标的任何建议?

回答by jfriend00

When you do:

当你这样做时:

self = this

You are implicitly creating a global variable which (since it's global) will have the same value for all instances. Local variables, must have var, letor constin front of them like one of these:

您正在隐式地创建一个全局变量(因为它是全局的)对于所有实例都具有相同的值。局部变量,必须有varletconst在它们前面像以下之一:

var self = this;
const self = this;
let self = this;

But, that isn't your solution here. You need to be using thisinstead. And, if you're going to supply a callback for the websocket and you want the person associated with that, I would suggest you just put a reference to the Person object on the websocket so you can then retrieve it from there. And, what's with all the missing semicolons to end each statement? Anyway, here is some fixed up code:

但是,这不是您的解决方案。您需要改为使用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
    }
}

回答by DashK

When declaring variables in Javascript, if you don't put a varin front, it'll be treated as a global variable, which causes some problem in your case.

在 Javascript 中声明变量时,如果您不将 avar放在前面,它将被视为全局变量,这在您的情况下会导致一些问题。

While the constructor is behaving as expected, you may want to do the following instead, so nameis saved to the instance of Person you are creating:

当构造函数按预期运行时,您可能需要执行以下操作,因此name将保存到您正在创建的 Person 实例中:

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

In addition, in WebSocket.onopen, 'this' changes from the instance of a Person to the instance of a WebSocket. You'll need to preserve the 'Person' in order to reference it inside WebSocket.onopen.

另外,在WebSocket.onopen中,'this'从Person的实例变成了WebSocket的实例。您需要保留“人”以便在 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); 
        };
    }
};

Hope this helps! Here's a JSFiddle to go with it: http://jsfiddle.net/WFdbe/

希望这可以帮助!这是一个与之配套的 JSFiddle:http: //jsfiddle.net/WFdbe/

回答by Raynos

self = this

self = this

Your creating a global variable, that's why your code is broken.

您创建了一个全局变量,这就是您的代码被破坏的原因。

Also trying to reference selfinside the prototype does not work, use this

也试图self在原型内部引用不起作用,使用this

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

Person.prototype = {
    openConnection : function(host, port){
        this.pointCount = 0
        this.ws = new WebSocket("ws://" + host + ":" + port)
        this.ws.onopen = this.onOpenConnection.bind(this)
    },
    constructor: Person,    
    onOpenConnection : function()   {
        console.log(this) // prints the person
        this.ws.send(this.name) // works only if one person exists
    }
}