In javascript need help wrapping a function and handling "this" properly

I started trying to create a timer function that would let me wrap a callback function so that I could later alter the behavior dynamically.

This led to a general realization that I really don't understand functions yet, and definitely don't understand what is happening with 'this'

I have a test environment setup on jsfiddle

myns = {};
myns.somefunc = function(txt) {
    this.data = txt;
    this.play = function() {
        alert(this.data + ' : '+dafunc.data);
    };
};

var dafunc = new myns.somefunc('hello world');

myns.Timer = function(msec, callback) {
    this.callback = null;
    this.timerID = null;

    this.ding = function() {
        this.callback();
    };

    this.set1 = function( msec, callback ) {
        this.stop();
        this.callback = callback;
        this.timerID = setTimeout(this.ding, msec );
    };

    this.set2 = function( msec, callback ) {
        this.callback = callback;
        var wrappedDing = (function(who) {
            return function() {
                who.ding();
            };
        })(this);
        this.timerID = setTimeout(wrappedDing, msec );
    };
    //this.set1(msec, callback);
    this.set2(msec, callback);    
};

var ttimer = new myns.Timer(1000, dafunc.play);

If I use the set1 method, then the callback doesn't work. So I am trying the set2 method. This gets me to the play method but "this" is not referring to the instance of somefunc.

I thought I was on the right track, but the mix up on 'this' has me confused.

Any clues would be welcome.

Answers


The problem is that, unlike in a language like python, when you take a dafunc.play and pass it somewhere else (callback = dafunc.play) it forgets it was associated with dafunc, son you you would need to use yet another wrapper function, like you did in the set2 function.

var ttimer = new myns.Timer(1000, function(){ return dafunc.play(); });

Making all there extra functions by yourself is annoying. You could instead use the bind method that is available in newer browsers:

var wrappedDing = this.ding.bind(this);

new myns.Timer(1000, dafunc.play.bind(dafunc) );

Or you could use a similar shim if you need to support older versions of IE too.


Finally, if you are not going to take advantage of some form of inheritance or dynamic binding, you could instead rewrite your code to use closures. Since everything is lexicaly scoped, you don't have to worry about the this anymore:

(btw, I ended up simplifying the code in the proccess...)

myns = {};

myns.somefunc = function(txt) {
    var obj = { data : txt };
    obj.play = function() {
        alert(obj.data);
    };
    return obj;
};

var dafunc = myns.somefunc('hello world');

myns.timer = function(msec, callback) {
    var timerID = null;

    var set = function(){
        stop();
        timerID = setTimeout(callback, msec);
    };

    set();

    return { 
         set: set
    };
};

var ttimer = myns.timer(1000, dafunc.play);

And one last thing: If you don't hate yourself use console.log and your browser's debugger and development console instead of using alerts for output.


Need Your Help

Python signal woes: SIGQUIT handler delays execution if SIGQUIT received during execution of another signal handler?

python signals

The following program is very simple: it outputs a single dot each half a second. If it recieves a SIGQUIT, it proceeds to output ten Qs. If it recieves a SIGTSTP (Ctrl-Z), it outputs ten Zs.

How to switch card positions in Card Deck shuffle() for Bridge game

java

So first of all I have a deck which has numbers 2-14 as Clubs or [0]-[12] in the Card [] object, and values(rank) 2-14 so on for Diamonds [13]-[25], Hearts [26]-[38], Spades [39]-[51].