JavaScript: Bind & Closure

JavaScript: Bind & Closure

In JavaScript, a bound function means that the original function definition is essentially wrapped in another function definition; however, the inner function gets returned out from the outer function, thus creating closure and permanently binding the context. Consider this simplified version of bind:

Function.prototype.bind = function(context) {
  const fn = this;
  return function() {
    return fn.call(context);
  };
};

Why is this important?

It makes code reuse possible and easy while locking in the keyword this to a specific context, which can help mitigate bugs. Consider this simple example:

const bassist = {
  name: 'Paul',
  spouse: 'Linda'
};
const guitarist = {
  name: 'John',
  spouse: 'Yoko'
};
const sayName = function() {
  return `Hi, I’m in The Beatles. My name is ${this.name}!`;
};
sayName(); // what is 'this'?
const sayNameBassist = sayName.bind(bassist);
sayNameBassist(); // 'Hi, my name is Paul!'
// compared to…
guitarist() // TypeError: guitarist is not a function

So, if there was a need to reuse more complex code, or utilize the this keyword in ambiguous circumstances, then using bound functions is very helpful. For example, in React, bound functions are common since callbacks make use of their contexts to commonly refer to a component’s state.

So, What is Closure?

Getting back to closure: closure is when an inner function has reference to the original scope in which it was defined, even though that function has been returned out from an outer function (such as in .bind() ).

This is helpful for not only creating a permanently bound context, but also to maintain and reference data that, for example, may have had high time complexity to create. Therefore, it’s one way to create a cache of data throughout the execution of the program.

Finally, here is a more robust version of bind:

Function.prototype.bind = function(context) {
  const fn = this;
  const outerArgs = Array.prototype.slice.call(arguments, 1);
  return function() {
    const allArgs = outerArgs.concat(arguments);
    return fn.apply(context, allArgs);
  };
};