1

I have the following Javascript code, and I'm trying to get a callback to work as shown below. I want to see an alert with "123" in it.

var A = function(arg){
    this.storedArg = arg;
    this.callback = function(){ alert(this.storedArg); }
}

var B = function() {
    this.doCallback = function(callback){ callback(); }
}       

var pubCallback = function(){ alert('Public callback') };

var a = new A(123);
var b = new B();

b.doCallback(pubCallback); // works as expected
b.doCallback(a.callback);  // want 123, get undefined

I understand what is happening but I'm not sure how to fix it. How can I get a callback function that references my a object? In my case, I can make changes to A but not B.

Watusimoto
  • 1,773
  • 1
  • 23
  • 38

6 Answers6

2

So what you want is to pass the context to the doCallBack.

E.g.

doCallBack = function (callback, callee) { 
    callback.apply(callee);
}

So then you would do:

b.doCallBack(a.callback, a);

If you cannot modify the B then you can use closure inside A:

var A = function (arg) {
    var self = this;
    this.storedArg = arg;
    this.callback = function () { alert(self.storedArg); }
}
Konstantin Dinev
  • 34,219
  • 14
  • 75
  • 100
2

You can create a variable that holds the wanted scope for this by putting it into variable that

var A = function(arg){
    this.storedArg = arg;
    var that = this; // Add this!
    this.callback = function(){ alert(that.storedArg); }
}

Working demo here: http://jsfiddle.net/vdM5t/

1

I understand what is happening (during the 2nd callback, "this" is b and not a)

No, JS is no class-based language where something could happen. If function(){ alert(this.storedArg); is just called as callback(); (like in b.doCallback), the this keyword points to the global object (window).

To get around that, you'd have to change A to

var A = function(arg){
    var that = this; // store reference to the current A object
    this.storedArg = arg;
    this.callback = function(){
        alert(that.storedArg); // and use that reference now instead of "this"
    };
}

If you don't expect the storedArg property to change, you could even make it more simple:

var A = function(arg){
    this.storedArg = arg;
    this.callback = function(){
        alert(arg); // just use the argument of the A function,
                    // which is still in the variable scope
    };
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Yes, you are correct; I had done some logging that showed this == b, but my statement did not make it clear where I had observed that. – Watusimoto Oct 15 '12 at 15:18
1

You need to pass the context you want the callback to execute in:

var B = function() {
    this.doCallback = function(callback, context) {
        callback.apply(context); 
    };
};

b.doCallback(a.callback, a); // 123

http://jsfiddle.net/a9N66/

jbabey
  • 45,965
  • 12
  • 71
  • 94
1

Because inside A.callback function, this does not refer to A but to window object.

var A = function(arg){
    this.storedArg = arg;
    this.callback = function(){ alert(this.storedArg); }
    -----------------------------------^-----------------
}

You can try this,

var A = function(arg){
    this.storedArg = arg;
    var that = this;
    this.callback = function(){ alert(that.storedArg); }
}

var B = function() {
    this.doCallback = function(callback){ callback(); }
}       

var pubCallback = function(){ alert('Public callback') };

var a = new A(123);
var b = new B();

b.doCallback(pubCallback); // works as expected
b.doCallback(a.callback);  // alerts 123
Jashwant
  • 28,410
  • 16
  • 70
  • 105
  • `this` does not refer to `A.callback` (which btw does not exist), and neither should it refer to `A`. – Bergi Oct 15 '12 at 14:58
0

When you do this:

b.doCallback(a.callback);

that just calls a's callback function without telling it to use a for this; so the global object is used for this.

One solution is to wrap that callback up:

b.doCallback(function() { a.callback(); });

Other solutions include binding the callback to a, using jQuery.proxy() (which is just a fancy way of doing my first solution), or passing in a to doCallback and invoking callback on a using apply.

andytuba
  • 187
  • 9