防抖节流的this写错地方了吗?

785 阅读2分钟

匿名函数内的this不是指向window吗

常用的定时器手写防抖节流函数

function debounce(fn, delay) {
    var timer; 
    return function () {
        var _this = this; // 在匿名函数内取了this
        var args = arguments;
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(function () {
            fn.apply(_this, args); // 将this传给fn
        }, delay);
    };
}
function throttle(fn, delay) {
   console.debug('throttle this', this);
    let canUse = true;
    return function() {
      if (canUse) {
        fn.apply(this, arguments); // 将匿名函数的this传给fn
        canUse = false;
        setTimeout(() => (canUse = true), delay);
      }
    };
}

这两个函数,都将匿名函数的this,传递给了fn

那么问题来了:
这里传this,是匿名函数内部的this。
匿名函数没有绑定到任何对象,内部的this应该是指向window吧?
window对象绑定给fn? 这好像没必要吧?

而且,这里不是想把throttlethis绑定给fn吗,那为什么不在匿名函数外取this呢?
防抖节流的this写错地方了吗?

为了探究这个问题,我以throttle函数为例,给各个函数绑定了不同对象。

给各函数绑定对象,查看this输出结果

  const a = {};
  const b = {};
  a.throttleInA = function throttle(fn, delay) {
    console.debug('throttle this', this);
    let canUse = true;
    return function() {
      console.debug('匿名函数 this', this); 
      //作为返回的匿名函数,指向调用该事件函数  谁调用,这个this指谁
      if (canUse) {
        fn.apply(this, arguments);
        canUse = false;
        setTimeout(() => (canUse = true), delay);
      }
    };
  };
  function fn() {
    console.debug('fn this', this);
  }

  b.throttleFuncB = a.throttleInA(fn);

  b.throttleFuncB();

在以上代码中,
throttle函数绑定了对象a,为 a.throttleInA
调用函数绑定对象b,为b.throttleFuncB
传入的函数fn,将会打印出fn内部的this,即匿名函数内给fn绑定的this

按照之前的分析,
throttle this 打印出来的this是指向对象a
匿名函数的this 指向window
绑定了匿名函数thisfn 也指向window

最终打印结果如下:

可以发现, throttle函数的this,指向的是对象a,意料之中
匿名函数内部的this,指向的是对象b,不是对象a,也不是window
绑定了匿名函数thisfn,指向对象b

怎么回事?

匿名函数的this,指向了调用它的对象

该匿名函数,作为返回值,返回给了对象b。 因此,匿名函数内部的this,也指向了对象b

也就是说,给fn绑定的this,既不是window,也不是throttle函数的对象a
而是调用该节流函数的对象b
这样,对象调用防抖节流时,fn可以获取对象的this