简体   繁体   中英

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM