doqtor
doqtor

Reputation: 8484

Prototypes and callbacks

I'm now in the process of transforming several functions into prototypes and I'm stuck on callbacks. Below is a minimal example of what I want to achieve:

WebSocketClient.prototype.send = function(t, data)
{
    this.ws.send(data);
    this.ws.onmessage = function(evt)
    {
        var msg = evt.data;
        var jsonData = JSON.parse(msg);
        if(jsonData["callback"] !== 'undefined' && jsonData["callback"] !== "") // jsonData = {callback:"on_test", data:[0,1,2]}
        {
            // How to transform callback into call ???
            var fn = window[jsonData["callback"]]; // == undefined
            if(typeof fn === 'function')
                fn(jsonData["data"]);
        }
    };
};

function Test()
{
    this.wc = new WebsocketClient();
    // here ws.connect, etc.
}

Test.prototype.send = function()
{
    this.wc.send(test, '{request:"get_data", callback:"on_test"')
}

Test.prototype.on_test = function(arr)
{
    // ...
}

var test = new Test();
test.send();

I want to make a call to t.callback(data) but can't figure out how to do this? I tried:

window[jsonData["callback"]]; // == undefined
window['Test.prototype.' + jsonData["callback"]]; // == undefined
window['Test.' + jsonData["callback"]]; // == undefined

Upvotes: 0

Views: 88

Answers (2)

Bogie
Bogie

Reputation: 153

If your function is in the global scope you could use

window.call(this, 'functionName',  arguments)

In your case,

window.call(this, jsonData['callback'], jsonData['data'])

By doing that, the callback will be invoked with jsonData['data'] as a parameter.

If the function is within an object test, just use

test.call(this, 'on_test', jsonData['data'])

Upvotes: 0

Michael Antipin
Michael Antipin

Reputation: 3532

There must be an error here:

Test.prototype.send = function()
{
    // use 'this' instead of 'test'
    // this.wc.send(test, '{request:"get_data", callback:"on_test"')
    this.wc.send(this, '{request:"get_data", callback:"on_test"')
}

And since on_test() is defined on Test.prototype, call it this way:

WebSocketClient.prototype.send = function(t, data)
{
    this.ws.send(data);
    this.ws.onmessage = function(evt)
    {
        var msg = evt.data;
        var jsonData = JSON.parse(msg);
        if(jsonData["callback"] !== 'undefined' && jsonData["callback"] !== "") // jsonData = {callback:"on_test", data:[0,1,2]}
        {
            var fn = t[jsonData["callback"]]; // t will be available in this scope, because you've created a closure
            if(typeof fn === 'function') {
                fn(jsonData["data"]);
                // OR, preserving scope of Test class instance t
                fn.call(t, jsonData["data"]);
            }
        }
    };
};

UPDATE: And be wary, that by calling fn(jsonData["data"]); you are loosing the original scope of the method. This way, this inside the on_test() method will point to global scope. If this is undesired, use call() (see corrected above).

Upvotes: 3

Related Questions