Reputation: 8839
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();
Are this1
, this2
, and this3
not the same? What is the intention of fn.apply()
? Why do we choose to fn.apply(this2)
and not just fn()
or fn.apply(this1)
or fn.apply(this3)
in this case?
Upvotes: 2
Views: 946
Reputation: 6546
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();
Upvotes: 3
Reputation: 31682
1.
The function may get attached to an object, so when calling the function the context should be that object. The function that get attached to such object is not fn
, it's the anonymous function returned by debounce
. So when calling fn
we have to call it with the same context as that anonymous function using either call
or apply
.
2.
The function that actually get called is the anonymous function, that will then call fn
after some time. Since we don't know how many arguments does fn
have, we just call it with all the arguments that the anonymous function get called with using the arguments
object and aplly
(call
won't be used here as it takes separate argument not grouped-in-array-like arguments).
The thisN question:
No, they're not the same.
this1
is going to be window
as debounce
is not attached to any object.
this2
could be window
or could be anything else depending on how you call debounce
:
var f = debounde(someFn, 100); // this2 is window
var obj = {};
obj.f = debounce(someFn, 100); // this2 is obj
this3
is also window
, due to this.
Upvotes: 3