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

setTimeout use closure context in strange way

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

debounce 函数确保:

  1. 延迟期间my_func只能执行一次
  2. my_func 不会早于 delay 毫秒
  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"

您可以尝试类似的方法:

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

当您第一次调用 debounced.call(11)that == 11 在调用上下文中 !scheduled == true 在此上下文中设置超时

下一个调用 debounced.call(22) 将 22 存储为本次调用上下文中的值,这与调用 setTimeout 的那个不同。

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