2

I'm studying the post for a solution to debouncing:

Can someone explain the "debounce" function in Javascript

I'm struggling to think of a situation where

func.apply(context, arguments);

is necessary, instead of just using

func();

I think 99% chances that it will only be used as a function. Under what circumstances will this be attached to an object? Can someone please show an example here? Thanks.

Community
  • 1
  • 1
Jinghui Niu
  • 990
  • 11
  • 28
  • `function() { console.log("hello "+ this.name); }` this is a function which uses context `function.call({name: "bob"})` this will make it alter its output. A non-trivial example `Array.prototype.slice.call(arguments)` is a very common pattern that calls `slice` with a context of the `arguments` object to produce an array. Simply put, some functions use a context, in which case `call`/`apply` can very well supply it, other functions don't, in which case setting the context makes no difference. Thus not setting the context will make some invocations fail. Adding it is more generic. – VLAZ Aug 15 '16 at 19:02
  • @Vid I appreciate the quick comment, but I'm really not asking about how context works. I'm curious about an example where this debouncing function is used as a method rather than a plain function. I just don't see any use of using "apply" here. Thank you for your comment though. – Jinghui Niu Aug 15 '16 at 19:08
  • Well, you don't KNOW what function is going to be debounced. It could be one with or without context, hence why adding the context is useful. You cannot guarantee that a function will or will not be using context when debounced. – VLAZ Aug 15 '16 at 19:18
  • 1
    not to mention preserving the arguments – aw04 Aug 15 '16 at 19:19
  • ^ what @aw04 said, too. I was focusing on the context, but in reality, the arguments are probably going to be relevant more times than that. – VLAZ Aug 15 '16 at 19:24

2 Answers2

1

debounce is intended to work with functions that are called in any manner. If the function being debounced is called with a context or with arguments, those need to be passed through when it's called with debounce.

So if you would normally make a call like:

foo.method(arg1, arg2);

then you should also be able to write:

debounced_method = debounce(foo.method);
foo.debounced_method(arg1, arg2);

Then when it calls the method, it receives this = foo and arguments = arg1, arg2.

Barmar
  • 741,623
  • 53
  • 500
  • 612
1

There are two things going on here in regards to the use of apply:

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, 
        args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(function() {
             timeout = null;
             if (!immediate) func.apply(context, args);
        }, wait);
        if (immediate && !timeout) func.apply(context, args);
     }; 
};

First, the context is being captured outside of the setTimeout callback. So whatever this binding rule is used to determine the initial context (which is dependent on how the depounced function is called later), it is being passed through to the callback function.

Alternately, you could do something like:

setTimeout(function() {
  ...
  func.apply(this, args);
}.bind(this), wait);

The second thing happening is the preservation of the arguments. apply here is used as a way to transfer the arguments (again, importantly captured outside the setTimeout callback) that you would pass to the original function. Because it takes an array (as opposed to call), it makes for an easy transfer.

So if you had something like like:

debouncedFunction(a, b)

The inner func is called appropriately as func(a, b).

aw04
  • 10,857
  • 10
  • 56
  • 89
  • Thanks very much for your detailed explanation. Now I can understand the context part. But with the arguments part, isn't simply calling a function like a better way: func(args)? Why bother with apply to just pass arguments? – Jinghui Niu Aug 15 '16 at 21:40
  • 1
    So the key is that apply allows you to pass all ages as an array. The way you're doing it, imagine a function that takes two or three args. The first would be an array of the args, and the others would be undefined... which is obviously not what you want. Does that make sense? – aw04 Aug 15 '16 at 21:55