Using function.bind to Create New Functions

Description

The bind() function creates a new bound function. Calling the bound function generally results in the execution of the function it wraps, which is also called the target function. The bound function will store the parameters passed - which include the value of this and the first few arguments - as its internal state. These values are stored in advance, instead of being passed at call time. You can generally see const boundFn = fn.bind(thisArg, arg1, arg2) as being equivalent to const boundFn = (...restArgs) => fn.call(thisArg, arg1, arg2, ...restArgs) for the effect when it's called (but not when boundFn is constructed).

A bound function can be further bound by calling boundFn.bind(thisArg, /* more args */), which creates another bound function boundFn2. The newly bound thisArg value is ignored, because the target function of boundFn2, which is boundFn, already has a bound this. When boundFn2 is called, it would call boundFn, which in turn calls fn. The arguments that fn ultimately receives are, in order: the arguments bound by boundFn, arguments bound by boundFn2, and the arguments received by boundFn2.

"use strict"; // prevent `this` from being boxed into the wrapper object

function log(...args) {
  console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // "this value", 1, 2, 3, 4, 5, 6

A bound function may also be constructed using the new operator if its target function is constructable. Doing so acts as though the target function had instead been constructed. The prepended arguments are provided to the target function as usual, while the provided this value is ignored (because construction prepares its own this, as seen by the parameters of Reflect.construct). If the bound function is directly constructed, new.target will be the target function instead. (That is, the bound function is transparent to new.target).

class Base {
  constructor(...args) {
    console.log(new.target === Base);
    console.log(args);
  }
}

const BoundBase = Base.bind(null, 1, 2);

new BoundBase(3, 4); // true, [1, 2, 3, 4]

However, because a bound function does not have the prototype property, it cannot be used as a base class for extends.

class Derived extends class {}.bind(null) {}
// TypeError: Class extends value does not have valid prototype property undefined

When using a bound function as the right-hand side of instanceof, instanceof would reach for the target function (which is stored internally in the bound function) and read its prototype instead.

class Base {}
const BoundBase = Base.bind(null, 1, 2);
console.log(new Base() instanceof BoundBase); // true

The bound function has the following properties:

length

The length of the target function minus the number of arguments being bound (not counting the thisArg parameter), with 0 being the minimum value.

name

The name of the target function plus a "bound " prefix.

The bound function also inherits the prototype chain of the target function. However, it doesn't have other own properties of the target function (such as static properties if the target function is a class).