Javascript’s call, apply and bind methods

I’ve been mulling over getting this post up for a while now – simply because functions are a big deal in Javascript. Javascript functions are packed with so many properties, methods and it’s fundamental nature requires some quality time in understanding its features.

There are a few things to keep in mind when dealing with Javascripts call(), apply, and bind methods()

  • call(), apply() and bind() are three methods every function has access too
  • bind() creates a copy of the function object in question
  • call(), apply() and bind() methods are methods that allow an object to point to a different ‘this’ variable when invoked.
  • Common patterns used in conjunction with call(), apply() and bind() are function borrowing and function currying.

Let’s check out a few examples mentioned in the items above.

Basic usage of the bind() method

I’m a big fan of the game Clash Royale so I’m going to be some contextual lingo from the game.

But first, let’s attempt to run a process without using call(), apply() and bind() and see how it behaves:


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

var logCard = function(card1, card2) {

  console.log('Logged: ' + this.getCardDetails);

}

logCard(); // this will output `undefined is not a function`

So the above code actually returns an error – this is no good. The ‘this’ variable in this case is referencing the global variable ‘window’ and ‘this.getCardDetails()’ is sort of just lost – it detached within the confines of scope. It’s floating by itself basically.

So how do we get this to work? Well, first let’s use bind().

Let’s try again


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

var logCard = function(card1, card2) {

  console.log('Logged: ' + this.getCardDetails());

}

// make a copy of logCard and store it in logCardDeck
// and the 'this' variable is now 'deck'
// the javascript engine now decides 'deck' is the 'this' variable
var logCardDeck = logCard.bind(deck);

logCardDeck(); // will output Logged: Electro Wizard 5

Notice the comment I added above “Logged: Electro Wizard 5”, we get this output when the code is run – this is the bind() method doing it’s job. Also notice we didn’t pass any arguments for “card1″ and card2” – we don’t get an error unless we log those arguments.

Ok, let’s runt he same code – this time pass in parameters for “card1” and “card2”


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

var logCard = function(card1, card2) {

  console.log('Logged: ' + this.getCardDetails());

}

// make a copy of logCard and store it in logCardDeck
// and the 'this' variable is now 'deck'
// the javascript engine now decides 'deck' is the 'this' variable
var logCardDeck = logCard.bind(deck);

logCardDeck('Fireball', 'Hog Rider'); 

// will output:
// Logged: Electro Wizard 5
// Cards: Fireball,Hog Rider

In that last example we passed in some parameters, so now we get “Cards: Fireball,Hog Rider” in addition to our original output.

Nice, so now we got a basic handle on bind(), we can ease into getting to know apply() and call().

The main difference is unlike bind() in which we create a copy of an object, call() and apply() actually executes it on the fly. Let’s see this in action.

Using call()


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

var logCard = function(card1, card2) {

  console.log('Logged: ' + this.getCardDetails());
  console.log('Cards: ' + card1+','+ card2);
}

logCard.call(deck, 'Fireball', 'Hog Rider');

// will output:
// Logged: Electro Wizard 5
// Cards: Fireball,Hog Rider

Let’s do the same thing with apply() – the only difference is we’re passing an array type instead of a comma separated string as function arguments.


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

var logCard = function(card1, card2) {

  console.log('Logged: ' + this.getCardDetails());
  console.log('Cards: ' + card1+','+ card2);
}

logCard.call(deck, ['Fireball', 'Hog Rider']);

// will output:
// Logged: Electro Wizard 5
// Cards: Fireball,Hog Rider

Notice in the case above, we are passing “[‘Fireball’, ‘Hog Rider’]” as an array not as a string – “‘Fireball’, ‘Hog Rider’.

Using apply() with an IIFE (Immediately Invoked Function

I don’t think I covered IIFE’s in detail, this concept requires it’s own post – or even chapter for that matter. In this next example, we could see apply() being used in conjunction with IIFE’s.


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

(function(card1, card2) {

  console.log('Logged: ' + this.getCardDetails());
  console.log('Cards: ' + card1+','+ card2);

}).apply(deck, ['Fireball', 'Hog Rider']);

// will output:
// Logged: Electro Wizard 5
// Cards: Fireball,Hog Rider

Yeah that above code looks a little cryptic – trust me I had the same reaction but this is totally possible with javascript. We are invoking a function on the fly and calling a function on the fly while passing it parameters then outputting its results – ALL AT THE SAME TIME. Yeah I know. It’s like whoa, dude.

Alright now onto function borrowing and function currying, first let’s tackle function borrowing.


var deck = {
  card: 'Electro Wizard',
  level: 5, 
  getCardDetails: function() {
    var getCard = this.card + ' ' + this.level;
    return getCard;
  }
}

var deck2 = {
  card: 'Ice Wizard',
  level: 9
}

// deck2 doesn't have that "getCardDetails" method
// so let's borrow that method using apply()

console.log(deck.getCardDetails.apply(deck2));

// above will output
// "Ice Wizard 9"

So you can borrow, or grab methods from other objects and functions – as long as you have similar property names.

Function currying – has to do with the bind() function. Creates a copy of a function


function multiple(a, b) {

  return a * b;

}

var multipleByTwo = multiply.bind(this, 2);

console.log(multipleByTwo);

// will output 


In this final example, we aren’t using call() or apply() – where we are calling the function, we are first creating “memory space for it” and then executing it. This is useful when we’re “setting up” an operation or parameters permanently in memory space.

The last example the same thing as writing (the below) except with the bind() method – we are allowing a bit more flexibility.


function multipleByTwo(b) {

  var a = 2;
  return a * b;

}

There’s really two important concepts to remember in all this:

(1) bind() creates a copy of the function being curried in which parameters can be initially set or assigned
(2) call() and apply() immediately executes the function (or method) being borrowed.

This is a general overview of call(), apply() and bind() – I will write a separate post for each concept in future posts – stay tuned!