Shuwei
Shuwei

Reputation: 791

what's the point of declaring args and context in a debounce function

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

Answers (2)

Wes Harper
Wes Harper

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

Felipe Malara
Felipe Malara

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

Related Questions