setTimeout以奇怪的方式使用闭包上下文

时间:2015-07-29 18:35:47

标签: javascript closures

我有一个debounce函数,例如var debounced = debounce(my_func, delay);

debounce功能确保:

  1. 延迟期间my_func只能执行一次
  2. my_func不会在delay ms
  3. 之前调用

    所以这是:

    var debounce = function(fn, delay) {
    
        var scheduled;
    
        return function() {     
            var that = this; // save context
            console.log('this = ' + that);
    
            if (!scheduled) {
                scheduled = true;
                setTimeout(function() {
                    scheduled = false;  
                    //PROBLEM: `that` variable is always the same as on the first function call
                    console.log('executing... \nthis = ' + that);                   
                    fn.apply(that); //call function in saved context
                }, delay);
            }
        }
    }
    

    测试:

        var ctx;
        var debounced = debounce(function() {
          ctx = this;
        }, 10);
        debounced.call(11);
        debounced.call(22); // PROBLEM: it leads to function invoked with this == 11 instead of this == 22
    

    打印到控制台

    "this = 11"
    "this = 22"
    "executing... 
    this = 11" // INSTEAD OF "this = 22"
    

2 个答案:

答案 0 :(得分:1)

你可以尝试这样的事情:

var debounce = function(fn, delay) {
    var that = {};
    var scheduled, last_fn;

    return function() {     
        that.a = this;
        console.log('this = ' + that.a);

        if (!scheduled) {
            scheduled = true;
            setTimeout(function() {
                scheduled = false;
                console.log('executing... \nthis = ' + that.a);
                fn.apply(that);
            }, delay);
        }
    };
};

答案 1 :(得分:1)

当您在呼叫的上下文中第一次debounced.call(11)呼叫that == 11时,!scheduled == true会在此上下文中设置超时

下一个呼叫debounced.call(22)将22存储为此呼叫上下文中的呼叫,这与调用setTimeout的呼叫不同。

解决方案是将变量存储在debounced返回函数的上下文之外,正如Doron指出的那样。