Let`s add some names to functions
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();
Why .apply()?: Here debouncedFn holds the reference of functionX, that means if you execute debouncedFn, functionX will be executed. Now when you pass n number of parameters to debouncedFn, those can be retrieved in functionX via a reserved keyword arguments. Ultimately, you want your arguments to be supplied to fn, so for passing those arguments to fn we have to use apply(). For more info, please follow this link.
this1, this2, this3: debounce is always executed globally, that is why it's context is window, functionX() can be attached to an object, that is why context of functionX() will be object in which you are putting debouncedFn() and context of setTimeout is again window because of global execution. See following example for better understanding of context.
function debounce(fn, delay) {
let timer = null;
console.log('this1', this.name);
return function() {
let context = this,
args = arguments;
console.log('this2', this.name);
clearTimeout(timer);
timer = setTimeout(function() {
console.log('this3', this.name);
fn.apply(context, args);
}, delay);
}
}
var person = {
name: 'John',
age: 23,
getName: debounce(function() {
console.log('hi');
}, 50)
}
person.getName();
person.getName();