“apply” function in JavaScript


apply function calls a function with a given context (this) and arguments passed as a list (array). It is defined on the prototype of Function class. It is similar to call function in JavaScript except how it takes the arguments.

Function.prototype.apply

If the context is passed as null or undefined to apply then the function will be executed in the global context (window in the browser and global in node.js).

If the arguments passed is not an array, then the apply function will throw a type error CreateListFromArrayLike called on non-object.

Syntax

apply(thisArg, [arg1, …, argN])
  • thisArg – Optional – Value to be used as this (context) while calling the function.
  • [arg1, …, argN] – Optional – Array of arguments to be passed in the function.

Examples

    function greet(to, from) {
        console.log(`Hello ${to}, I am ${from}`);
    }

    greet();
    greet.apply(null, ['Tony', 'Steve']);
Hello undefined, I am undefined
Hello Tony, I am Steve
    const heroNickNames = {
        hulk: 'Green Goliath',
        spiderMan: 'Spidey',
        thor: 'Goldilocks'
    };

    function printHeroNickNames() {
        console.log(`
            Nick names of heroes:
            Hulk - ${this.hulk}
            SpiderMan - ${this.spiderMan}
            Thor - ${this.thor}
        `);
    }

    printHeroNickNames();
    printHeroNickNames.apply(heroNickNames);
            Nick names of heroes:
            Hulk - undefined
            SpiderMan - undefined
            Thor - undefined


            Nick names of heroes:
            Hulk - Green Goliath
            SpiderMan - Spidey
            Thor - Goldilocks
    // Using 'apply' to concatenate arrays
    const firstArray = [1, 2, 3, 4];
    const secondArray = [5, 6, 7, 8, 9];
    firstArray.push.apply(firstArray, secondArray);
    console.log(firstArray);
[
  1, 2, 3, 4, 5,
  6, 7, 8, 9
]

Can we write our own “apply” function?

Now that we have spread (…) operator in JavaScript, let’s try to write our own implementation of apply.

    Function.prototype.myApply = function (thisArg, args) {
        if (thisArg === null || thisArg === undefined) {
            thisArg = globalThis;
        }

        if (!Array.isArray(args)) {
            throw new Error('Argument must be an array');
        }

        const newFunction = this.bind(thisArg);
        return newFunction(...args);
    }
    const avengersTower = {
        availableHero: 'Hulk'
    };

    function assistHeroes(heroOne, heroTwo) {
        console.log(`${heroOne} and ${heroTwo} will be assisted by currently available hero: ${this.availableHero}`);
    }

    assistHeroes('AntMan', 'Hawkeye');
    assistHeroes.myApply(avengersTower, ['AntMan', 'Hawkeye']);
AntMan and Hawkeye will be assisted by currently available hero: undefined
AntMan and Hawkeye will be assisted by currently available hero: Hulk

Explanation

  1. Define a new function on prototype of Function class. We are doing this because we want our function to be available on functions rather taking them as argument.
  2. Check thisArg. Assign [globalThis] to thisArg if found [null] or [undefined].
  3. Check if the argument provided is an array or not.
  4. Get a new function bounded with new context (thisArg).
  5. Execute the new function by spreading the arguments and return the result.

References

  1. Mozilla Developer Network (MDN)