Reputation: 791
I've come across custom defined debounce function a few times, the majority of the tutorial writes a debounce function this way
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
I'm confused about the meaning of declaring context and args and use apply inside the anonymous return function. What's the point of declaring these two variables and use the apply later and pass in these two into the tobe executed function in debounce?
To me, all I can see is that it allows me to pass in parameters this way:
function myFunc(name) {
console.log('hello',name)
}
debounce(myFunc, 100)('Josh');
But isn't it the same as just pass it directly to myFunc, and write things this way:
debounce(myFunc('Josh'), 100);
Why would we need to use apply here?
Upvotes: 3
Views: 1425
Reputation: 172
The reason for this is that debounce is supposed to call a certain function after a specified amount of time. In order to invoke a function it needs a function reference. If you were to do something like:
debounce(myFunc('Josh'), 100);
myFunc('Josh')
is not actually a reference to the function myFunc
, but rather an evaluation of the function myFunc
. It may be useful to elaborate on this point with an example.
// this is a function definition
function add(num1, num2) {
return num1 + num2;
}
console.log(add); // `add` is a function reference
console.log(add(1, 1)); // 2 is the result of the function's evaluation
Given the above example, if you did debounce(add(1, 1), 100);
, you'd be asking the debounce function to invoke the value 2
after 100ms of inactivity. What you'd really like to do is invoke the function add
, but in order to do so you need to pass a reference to the function: debounce(add, 100)
. The problem is now that we are unable to pass parameters to the add function, which is where currying comes in handy.
Declaring the anonymous function is a way to control the scope and context of the method that will be called. It creates a closure, where all of its variables and state will continue to exist until the function is done executing. For instance, if you're applying the debounce function to an input field, the arguments may be different each time the user triggers the debounce function. Keeping args
within the closure allows each new function to "remember" its own arguments.
As to why you would want to use .apply
, that is simply because arguments is an array of values, so if you'd like to call your method with multiple individual arguments, you'd need to use .apply
as in this example.
Upvotes: 1
Reputation: 1914
You can't pass the arguments directly to the function to be executed because those arguments can only achieved when the function debounce is called, these arguments are been actually passed implicitly to the function inside the debounce function Here
return function ()
Even though this function doesn't appear to receive any arguments, you can pass arguments to it and retrieve those arguments trough calling this variable:
args = arguments // here they are
And for the last question, why you need to use apply?
It's because whenever you are dealing with some implicit call, just as
document.addEventListener('click', myFunc.bind(this)) // Implicit here
Or like in your case
debounce(myFunc, 100)
You must bind the necessary context to this implicit call.
And in your case, you're only receiving this context when you're actually calling the debounce. With this implementation the context passed to the the inner function is the same context from where you're calling the debounce function. If you hadn't use the apply, the context of the inner function would be limited to the debounce function scope and not the scope from where debounce is called
Upvotes: 1