在进行辩论时,fn.apply(context,args)有什么意义?

时间:2017-11-25 02:01:09

标签: javascript

function debounce(fn, delay) {
  let timer = null;
  // this1
  return function() {
    let context = this, args = arguments;
    // context = this2
    clearTimeout(timer);
    timer = setTimeout(function() {
      // this3
      fn.apply(context, args);
    }, delay);
  }
}

var debouncedFn = debounce(function() {
  console.log('hi');
}, 50);

debouncedFn();

this1this2this3不一样吗? fn.apply()的目的是什么?在这种情况下,为什么我们选择fn.apply(this2)而不只是fn()fn.apply(this1)fn.apply(this3)

2 个答案:

答案 0 :(得分:2)

  1. 保留去抖动函数的上下文(值)。
  2. 处理未知数量的参数。
  3. <强> 1

    该函数可能附加到一个对象,因此在调用该函数时,上下文应该是该对象。附加到此类对象的函数不是fn,它是debounce返回的匿名函数。因此,在调用fn时,我们必须使用与callapply的匿名函数相同的上下文来调用它。

    <强> 2

    实际调用的函数是匿名函数,然后在一段时间后调用fn。由于我们不知道fn有多少个参数,我们只需使用arguments对象和aplly({call调用匿名函数调用的所有参数来调用它。 {1}}不会在这里使用,因为它需要单独的参数而不是类似数组的参数。)

    这个问题:

    不,他们不一样。

    this1将为window,因为debounce未附加到任何对象。

    this2可以是window,也可以是其他任何内容,具体取决于您拨打debounce的方式:

    var f = debounde(someFn, 100);   // this2 is window
    var obj = {};
    obj.f = debounce(someFn, 100);   // this2 is obj
    
    由于this

    this3也是window

答案 1 :(得分:1)

让我们为函数添加一些名称

function debounce(fn, delay) {
  let timer = null;
  return function functionX() {
    let context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function functionY() {
      fn.apply(context, args);
    }, delay);
  }
}

var debouncedFn = debounce(function functionZ() {
  console.log('hi');
}, 50);

debouncedFn();

为什么.apply()这里debouncedFn包含functionX的引用,这意味着如果您执行debouncedFnfunctionX将被执行。现在,当您将n个参数传递给debouncedFn时,可以通过保留关键字functionXarguments中检索这些参数。最终,您希望将参数提供给fn,因此要将这些参数传递给fn,我们必须使用apply()。有关详情,请按此link

this1, this2, this3: debounce始终全局执行,这就是为什么它的上下文为windowfunctionX()可以附加到{{1}这就是为什么object的上下文将成为functionX()的对象,而debouncedFn()的上下文由于全局执行而再次成为setTimeout的原因。请参阅以下示例以更好地理解上下文。

window