“bind” function in JavaScript


bind function returns a new function with its context (this) set to a given value. It prepends the arguments given to it to the arguments which are passed when calling the new function. It is defined on the prototype of Function class.

Function.prototype.bind

Syntax

bind(thisArg, arg1, …, argN)
  • thisArg – Value to be used as context (this) when calling the new function. As per MDN, if it is not provided then the execution scope will be used as thisArg for the new function.
  • arg1, …, argN – Optional – Arguments which will be prepended before the arguments passed in the new function.

Examples

    const starWars = {
        master: 'Obi-Wan Kenobi',
        disciple: 'Anakin Skywalker'
    };

    function printDetails() {
        console.log(`${this.master} trained ${this.disciple}`);
    }

    printDetails();

    const boundedPrintDetails = printDetails.bind(starWars);
    boundedPrintDetails();
undefined trained undefined
Obi-Wan Kenobi trained Anakin Skywalker
    const permanentTeam = {
        dev1: 'Mike',
        dev2: 'Ae-Cha',
        engineeringManager: 'William'
    };

    function printTeamDetails(...contractDevs) {
        console.log(`
        Permanent Members:
        Dev 1 - ${this.dev1}
        Dev 2 - ${this.dev2}
        Engineering Manager - ${this.engineeringManager}
        Contract Developers - ${contractDevs.join(', ')}
        `);
    }

    printTeamDetails('Alice', 'Adele');
    printTeamDetails.bind(permanentTeam, 'Angela', 'Edith')('Alice', 'Adele');
        Permanent Members:
        Dev 1 - undefined
        Dev 2 - undefined
        Engineering Manager - undefined
        Contract Developers - Alice, Adele


        Permanent Members:
        Dev 1 - Mike
        Dev 2 - Ae-Cha
        Engineering Manager - William
        Contract Developers - Angela, Edith, Alice, Adele

Can we write our own “bind” function?

Let’s see if we can have our own implementation of “bind” function.

    Function.prototype.myBind = function (thisArg, ...bindArgs) {
        if (thisArg === null || thisArg === undefined) {
            throw new Error('this not provided');
        }

        const originalFunction = this;
        const newFunction = function (...funcArgs) {
            const newContext = Object.create(thisArg);
            const allArgs = bindArgs.concat(funcArgs);

            newContext[originalFunction.name] = originalFunction;
            return newContext[originalFunction.name](...allArgs);
        }

        return newFunction;
    }

Let’s use the above example only to test out our implementation.

    const permanentTeam = {
        dev1: 'Mike',
        dev2: 'Ae-Cha',
        engineeringManager: 'William'
    };

    function printTeamDetails(...contractDevs) {
        console.log(`
        Permanent Members:
        Dev 1 - ${this.dev1}
        Dev 2 - ${this.dev2}
        Engineering Manager - ${this.engineeringManager}
        Contract Developers - ${contractDevs.join(', ')}
        `);
    }

    printTeamDetails('Alice', 'Adele');
    printTeamDetails.myBind(permanentTeam, 'Angela', 'Edith')('Alice', 'Adele');


        Permanent Members:
        Dev 1 - undefined
        Dev 2 - undefined
        Engineering Manager - undefined
        Contract Developers - Alice, Adele


        Permanent Members:
        Dev 1 - Mike
        Dev 2 - Ae-Cha
        Engineering Manager - William
        Contract Developers - Angela, Edith, Alice, Adele

Though we were able to create our own “bind” function, it should be noted that the above code is nowhere near to the original “bind” function and should be used only for learning purposes.

Explanation

  1. Define a new function on prototype of Function class. We are doing this because we want our function to be available on all functions rather taking them as argument.
  2. Check if thisArg is provided, throw an error if not. Original bind function, however, do not throw an error. We have added this for our simplicity only.
  3. Store the reference to the calling function (this) in a new variable.
  4. Create a new function which
    1. Creates a new object with its prototype set to thisArg. Why? Because we don’t want to make the original context (thisArg) dirty.
    2. Concatenates the arguments given in myBind and the new function.
    3. Adds the original function as a property to the new object.
    4. Executes the original function on the new object and return the result.
  5. Return the new function.

References

  1. Mozilla Developer Network (MDN)