1

It seems that this references in javascript don't work after a callbackfunction. When running this code:

new Bla().start();

function Bla(){
    this.start = function(){
        alert("starting");
        x(this.done);
    }

    this.done = function(){
        alert("done");
        try{
            this.postDone();
        }
        catch(e){
            alert(e);
        }
    }

    this.postDone = function(){
        alert("postdone");
    }
}

function x(callback){
    alert("x");
    try{
        callback();
    }
    catch(e){
        alert(e);
    }
}

The alerts will be as follows:

Starting
x
done
TypeError: undefined is not a function

I'd like to know why this problem exists, and preferably a best-practise to solve this.

Daan Luttik
  • 2,781
  • 2
  • 24
  • 37
  • `this` refers to the context, you're calling `done` from a different context. Or should we rather talk about [lexical environment](http://es5.github.io/#x10.2)? – Teemu Jan 03 '15 at 14:57

3 Answers3

3

change the x function call like this,

this.start = function(){
    alert("starting");
    x(this.done.bind(this));
}
Sampath Liyanage
  • 4,776
  • 2
  • 28
  • 40
0

you need to save the reference to that context as context changes here , see here how this stored in ref and passed into arguments and then called using ...

    new Bla().start();

    function Bla(){
        this.start = function(){
            alert("starting");
            x(this.done ,this);
        }

        this.done = function(){
            alert("done");
            try{
                var st = arguments[0];
                console.log(st); 
                st.postDone();
            }
            catch(e){
                alert(e);
            }
        }

        this.postDone = function(){
            alert("postdone");
        }
    }

    function x(callback,ref){
        alert("x");
        try{
          callback(ref);
        }
        catch(e){
            alert(e);
        }
    }

hope that helps...

Vishal Sharma
  • 2,773
  • 2
  • 24
  • 36
0

Functions don't intrinsically know about the "this" object. You only get a "this" object when a function is invoked through an object, e.g. obj.func(). Just calling func() will result in an undefined "this" object.

I can think of three possible solutions for your code:

Solution 1: Pass the "this" object with the callback, and invoke the callback on it with call() or apply()

...
function Bla(){
    this.start = function(){
        alert("starting");
        x(this.done,this);
}
...
function x(callback,object){
    alert("x");
    try{
        callback.apply(object);
    }
    catch(e){
        alert(e);
    }
}

http://jsfiddle.net/4gt2u0y9/

Solution 2: Pass the "this" object and the name of the function to call on it

...
function Bla(){
    this.start = function(){
        alert("starting");
        x(this,'funcName');
}
...
function x(object,funcName){
    alert("x");
    try{
        object[funcName]();
    }
    catch(e){
        alert(e);
    }
}

http://jsfiddle.net/4gt2u0y9/1/

Solution 3: Pass just the "this" object, and have the callback client assume the callback name

...
function Bla(){
    this.start = function(){
        alert("starting");
        x(this);
}
...
function x(callbackServer){
    alert("x");
    try{
        callbackServer.done();
    }
    catch(e){
        alert(e);
    }
}

http://jsfiddle.net/4gt2u0y9/2/

bgoldst
  • 34,190
  • 6
  • 38
  • 64