Search code examples
javascriptclosuresthis

In what cases, we want to use apply with this?


I understand how this works but cant understand why we want to use apply with "this" keyword as in a example below:

function curry(func) {
    return function curried(...args) {

        if (args.length >= func.length) {
            return func.apply(this, args)
        } else {
            return curried.bind(this, ...args)
        }
    }
}

Here bind and apply use "this" as a first argument, but what is the purpose if we can just do func(args) since this points to same lexical environment of a function. I can see some benefits with it with arrow functions but here I have named functions. There is no difference or I am missing something?


Solution

  • The reason for using apply is to keep the same the value of this. Calling func(args) would result in this being the window object (in non-strict mode) or undefined (in strict mode).

    Here's an example that breaks if you call func(args):

    function curry(func) {
      return function curried(...args) {
        if (args.length >= func.length) {
          return func(args);
        } else {
          return curried.bind(this, ...args);
        }
      };
    }
    
    const example = {
      multiplier: 5,
      calculate: function (a, b) {
        return (a + b) * this.multiplier;
      },
    };
    example.curriedVersion = curry(example.calculate);
    
    // Because of the way these are being called, `this` should be `example`
    console.log(example.calculate(1, 2));
    // But here it's not, causing unexpected results
    console.log(example.curriedVersion(1)(2));

    But it works if you do apply(this, args):

    function curry(func) {
      return function curried(...args) {
        if (args.length >= func.length) {
          return func.apply(this, args);
        } else {
          return curried.bind(this, ...args);
        }
      };
    }
    
    const example = {
      multiplier: 5,
      calculate: function (a, b) {
        return (a + b) * this.multiplier;
      },
    };
    example.curriedVersion = curry(example.calculate);
    
    // Because of the way these are being called, `this` should be `example`
    console.log(example.calculate(1, 2));
    console.log(example.curriedVersion(1)(2));