call/apply/bind

Definition

func.call(thisArg, arg1, arg2, ...)
func.apply(thisArg, [argsArray])
func.bind(thisArg[, arg1[, arg2[, ...]]])

Description

These three functions allow you to attach a function to an object to make it act like a method, where “this” represents the object.

call and apply are identical, except call accepts a dynamic number of parameters, while apply accepts an array of values.

Sample Code

const Line = function() {
    this._spaces = [];
    for (let i = 0; i < 10; ++i) { this._spaces[i] = "."; }

    this.turnOn = function(idx) { this._spaces[idx] = "X"; };
    this.turnOff = function(idx) { this._spaces[idx] = "."; };
    this.toString = function() { return this._spaces.join(""); }
};

const line = new Line();

const turnOnTwo = function (idx1, idx2) {
    this.turnOn(idx1);
    this.turnOn(idx2);
};

console.log(line.toString()); // ..........

call

// "c"all = "c"omma separated parameters
turnOnTwo.call(line, 3, 5);
console.log(line.toString()); // ...X.X....

apply

// "a"pply = "a"rray of items
turnOnTwo.apply(line, [0, 8]);
console.log(line.toString()); // X..X.X..X.

bind

const boundFunction = turnOnTwo.bind(line);
boundFunction(1, 2);
console.log(line.toString()); // XXXX.X..X.

Reference

Browser Requirements

call and apply are available anywhere. bind requires IE9+ or a real browser.

Polyfill

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}