JavaScript Functions - Part 3: Bind

As we have learned in part 1 of our series, functions are first class objects, which gives them full access to properties and methods. In part 2, we examined call and apply. In the following post we will cover another core method of the Function object, bind. Let’s dive in.

Definition

bind – method of the Function object that creates a new function that when called has it’s this value mapped to the given parameter and uses the set arguments.

bind returns a new function with the value of this locked (bound) to a function.

Syntax

aFunction.bind(thisValue, arg1, arg2,..., argN);

bound function

const boundFunction = myFunction.bind(thisValue);

bound function with a parameter

const boundFunctionWithParam = myFunction.bind(thisValue, param);

Why/when would you use this function?

  • you want to lock in the value of this, helpful for event handlers (see: example 1 and example 3)
  • you want to “partially apply” functions by locking in arguments (see: example 2)

Examples

Example 1 - locking in the value of this

this.name = "Global";
const component = {
  name: "Component",
  getName: function() {
    return this.name;
  }
};

const getName = component.getName;

console.log(getName()); // "Global"

const boundGetName = getName.bind(component);
console.log(boundGetName()); //"Component"

So what happened in our previous example? Why was “Component” printed and not “Global”? The reason is that we bound the this value to our component object. Even though the first call to getName() returns “Global”, we subsequently locked the value of this to the component in our bound function.

Example 2 - partial function application

We can also utilize bind to create a function with a predefined set of arguments.

function multiply(x,y) {
  return x * y;
}

//Create a function that will triple any number
const triple = multiply.bind(null,3);
console.log(triple(10));  //30

We have set the “x” value and pass in the value of “y” whenever we call our “triple” function. Notice in this example how we passed in null for the value of this and also passed in the values last (this follows our function signature).

Example 3 - using bind in event handling

This is a more complex example to highlight the usage of bind. Please be sure to read the comments as this example is showcasing a few different concepts.

<div class="navigation">
  <button class="button-help" name="help button">Help</button>
  <button class="button-back" name="back button">Back</button>
  <button class="button-next" name="next button">Next</button>
</div>
/**
 * Example illustrating usage of bind with event handlers
 */

/**
 * HeaderNavigation component
 * @example
 * const nav = new HeaderNavigation();
 */
const HeaderNavigation = (function() {
  'use strict';

  /**
   * Constructor
   */
  function Navigation() {
    this.name = 'navigation';
    this.init();
  }

  /**
   * Initialize our Navigation object
   * Get DOM elements for our nav: help, back, and next buttons
   * Add event listeners to each button
   */
  Navigation.prototype.init = function() {
    const nav = document.querySelectorAll('.navigation')[0];
    const buttonHelp = nav.querySelectorAll('.button-help')[0];
    const buttonBack = nav.querySelectorAll('.button-back')[0];
    const buttonNext = nav.querySelectorAll('.button-next')[0];

    //example of binding an anonymous function
    buttonHelp.addEventListener('click', function() {
        this.showHelp();            
    }.bind(this));

    //do not bind the value of "this" to the back button
    //notice that "back button" is printed to the screen, but
    //not "going to stage: ..."
    //NOTE: By hitting "F12" to see the developer tools console,
    //you will notice that there is an error
    //"TypeError: this.goToStage is not a function"
    //This occurs because the "this" in the case below refers
    //to the back button not to our Navigation
    buttonBack.addEventListener('click', this.click);

    //bind the click function to our Navigation Object
    //the "this" in .bind(this) refers to the Navigation Object
    buttonNext.addEventListener('click', 
                                this.click.bind(this, 'Stage 1'));
  };

  /**
   * Handle button click event
   * print the name of "this" (for tracking/testing)
   * go to the corresponding stage
   */
  Navigation.prototype.click = function() {
    console.log(`click: 'this' is the ${this.name}`);
    this.goToStage(arguments[0]);
  };

  /**
   * Print the stage we need to navigate to
   * @param {string} stage the stage to navigate to
   */
  Navigation.prototype.goToStage = function(stage) {
    console.log(`going to stage: ${stage}`);
  };

  Navigation.prototype.showHelp = function() {
    alert(`You are now being helped by the ${this.name} :)`);
  }

  return Navigation;
}());

//Instantiate an instance of HeaderNavigation
const nav = new HeaderNavigation();

Try out the example on CodePen

Conclusion

The Function object is a fundamental component of the JavaScript language and learning to leverage its bind method can help us simplify code and promote reusability. Through examples, we have observed how bind can be used to lock in the value of this, which is helpful to borrow functions and to ensure we are targeting the correct object in our programs (e.g. in event handlers). By leveraging bind we can also create partially applied functions that allow us to reuse arguments and functionality. For further reading, check out the additional resources below and be sure to try out your own examples.

Additional Resources

Updated: