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();
this1
,this2
和this3
不一样吗? fn.apply()
的目的是什么?在这种情况下,为什么我们选择fn.apply(this2)
而不只是fn()
或fn.apply(this1)
或fn.apply(this3)
?
答案 0 :(得分:2)
<强> 1 强>
该函数可能附加到一个对象,因此在调用该函数时,上下文应该是该对象。附加到此类对象的函数不是fn
,它是debounce
返回的匿名函数。因此,在调用fn
时,我们必须使用与call
或apply
的匿名函数相同的上下文来调用它。
<强> 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
的引用,这意味着如果您执行debouncedFn
,functionX
将被执行。现在,当您将n
个参数传递给debouncedFn
时,可以通过保留关键字functionX
在arguments
中检索这些参数。最终,您希望将参数提供给fn
,因此要将这些参数传递给fn
,我们必须使用apply()
。有关详情,请按此link。
this1, this2, this3:
debounce
始终全局执行,这就是为什么它的上下文为window
,functionX()
可以附加到{{1}这就是为什么object
的上下文将成为functionX()
的对象,而debouncedFn()
的上下文由于全局执行而再次成为setTimeout
的原因。请参阅以下示例以更好地理解上下文。
window