2

我开始尝试创建一个计时器函数,它可以让我包装一个回调函数,以便以后可以动态地改变行为。

这导致了一个普遍的认识,即我真的不了解函数,并且绝对不了解“this”发生了什么

我在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);

如果我使用 set1 方法,则回调不起作用。所以我正在尝试 set2 方法。这让我了解了 play 方法,但“this”并不是指 somefunc 的实例。

我以为我走在正确的轨道上,但是“这个”的混淆让我感到困惑。

任何线索都会受到欢迎。

4

1 回答 1

1

问题是,与 python 之类的语言不同,当您将 dafunc.play 传递给其他地方(回调 = dafunc.play)时,它会忘记它与 dafunc 相关联,儿子您需要使用另一个包装函数,就像您在 set2 函数中所做的那样。

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

自己制作所有额外的功能很烦人。您可以改用较新浏览器中可用的 bind 方法:

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

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

或者,如果您也需要支持旧版本的 IE,您也可以使用类似的 shim。


最后,如果您不打算利用某种形式的继承或动态绑定,您可以改写代码以使用闭包。由于所有内容都是词法范围的,因此您不必再担心this

(顺便说一句,我最终简化了过程中的代码......)

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);

最后一件事:如果您不讨厌自己,请使用 console.log 以及浏览器的调试器和开发控制台,而不是使用警报进行输出。

于 2012-05-02T00:35:33.397 回答