Call, Bind and Apply

Call, Bind and Apply

· 5 min read

tl;dr call, bind and apply are 3 really important methods that are available on all Javascript functions out of the box. Each method does the same kind of thing, but the invocations are different.

Prerequisites for this article

  • Understanding of this in Javascript (good luck with that one)
  • Knowledge of objects and functions
  • Ideally some Pokemon knowledge, but not essential
  • A strong cup of coffee. Or tea. Or whatever gets you through articles about this
  • A llama. For the vibes

Think of them like three siblings who all know how to cook but each one insists on doing it their own way. The food comes out the same, the process is just slightly different.

Call

call attaches this into a function, and then executes it immediately:

var pokemon1 = {
  name: "Gary",
  species: "Charizard",
  type1: "Fire",
  type2: "Flying",
  health: 1000,
  atk: 94,
};

var pokemon2 = {
  name: "Barry",
  species: "Blastoise",
  type1: "Water",
  type2: "",
  health: 1000,
  atk: 91,
};

function getFullName(connectingWord) {
  var fullName = this.name + connectingWord + this.species;
  return fullName;
}

getFullName.call(pokemon1, " is a "); // Gary is a Charizard getFullName.call(pokemon2, ' the ') // Barry the Blastoise

Apply

apply does the same thing as call, except it takes in an array of arguments. Thats literally the only difference. I know, you’d think it would be more dramatic:

var pokemon1 = {
    name: 'Gary',
    species: 'Charizard',
    type1: 'Fire',
    type2: 'Flying',
    health: 1000,
    atk: 94
};


var pokemon2 = {
    name: 'Barry',
    species: 'Blastoise',
    type1: 'Water',
    type2: '',
    health: 1000,
    atk: 91
};

function getAttacks(attack1, attack2) {
  console.log(this.name + " has the following attacks: ")
  console.log(attack1)
  console.log(attack2)

}

getAttacks.apply(pokemon1, ['Fire Spin', 'Blast Burn']) getAttacks.apply(pokemon2, ['Water Gun', 'Hydro Cannon'])

Quick way to remember the difference: Call takes Comma separated arguments. Apply takes an Array. Done.

Bind

To understand bind a little better, let’s go deeper using the above example:

var pokemon1 = {
  name: "Gary",
  species: "Charizard",
  type1: "Fire",
  type2: "Flying",
  health: 1000,
  atk: 94,
  attack: function () {
    return (
      Math.floor(Math.random() * (this.atk + 10 - this.atk + 1)) + this.atk
    );
  },
  getFullName: function () {
    var fullName = this.name + " the " + this.species;
    return fullName;
  },
};

var pokemon2 = {
  name: "Barry",
  species: "Blastoise",
  type1: "Water",
  type2: "",
  health: 1000,
  atk: 91,
  attack: function () {
    return (
      Math.floor(Math.random() * (this.atk + 10 - this.atk + 1)) + this.atk
    );
  },
  getFullName: function () {
    var fullName = this.name + " the " + this.species;
    return fullName;
  },
};

function startBattle(pokemon1, pokemon2) {
  console.log(pokemon1.getFullName() + " vs " + pokemon2.getFullName());
}

startBattle(pokemon1, pokemon2); // "Gary the Charizard vs Barry the Blastoise"

In the above example we can see there are some repeated methods as part of each object. It would be a lot clearer if we could define a function we can reuse on each Pokemon:

var pokemon1 = {
  name: "Gary",
  species: "Charizard",
  type1: "Fire",
  type2: "Flying",
  health: 1000,
  atk: 94,
  attack: function () {
    return (
      Math.floor(Math.random() * (this.atk + 10 - this.atk + 1)) + this.atk
    );
  },
};

var pokemon2 = {
  name: "Barry",
  species: "Blastoise",
  type1: "Water",
  type2: "",
  health: 1000,
  atk: 91,
  attack: function () {
    return (
      Math.floor(Math.random() * (this.atk + 10 - this.atk + 1)) + this.atk
    );
  },
};

function getFullName() {
  var fullName = this.name + " the " + this.species;
  return fullName;
}

function startBattle(pokemon1, pokemon2) {
  console.log(
    getFullName.bind(pokemon1)() + " vs " + getFullName.bind(pokemon2)()
  ); // "Gary the Charizard vs Barry the Blastoise"
}

startBattle(pokemon1, pokemon2);

Here you can see we’ve refactored the function to be standalone, and we are now invoking it using bind. This causes a copy of the pokemon object to be made. Unlike call and apply, bind doesnt execute the function straight away. It returns a new function with this baked in, ready to go whenever you call it. Like meal prepping but for functions.

Taking this example a step further, let’s see if we can refactor the attack function a little to demonstrate some other features of the bind function:

var pokemon1 = {
    name: 'Gary',
    species: 'Charizard',
    type1: 'Fire',
    type2: 'Flying',
    health: 1000,
    atk: 94
};


var pokemon2 = {
    name: 'Barry',
    species: 'Blastoise',
    type1: 'Water',
    type2: '',
    health: 1000,
    atk: 91
};

function getFullName() {
  var fullName = this.name + ' the ' + this.species;
  return fullName;
}

function attack(opponent) {
  const name1 = getFullName.bind(this)()
  const name2 = getFullName.bind(opponent)()

  const hit = Math.floor(Math.random() * ((this.atk + 10) - this.atk + 1)) + this.atk // Calulates attack damage using this
  opponent.health -= hit // Removes points from opponent

  console.log(name1 + " hits for " + hit + " points")
  console.log(name2 + "'s' health is " + opponent.health)
}

function startBattle(pokemon1, pokemon2) {
  console.log(getFullName.bind(pokemon1)() + ' vs ' + getFullName.bind(pokemon2)())
}

startBattle(pokemon1, pokemon2)

const pokemonOneAttack = attack.bind(pokemon1)
const pokemonTwoAttack = attack.bind(pokemon2)

pokemonOneAttack(pokemon2)
pokemonTwoAttack(pokemon1)

pokemonOneAttack(pokemon2)
pokemonTwoAttack(pokemon1)

console.log(pokemon1) console.log(pokemon2)

Using bind we’ve now managed to create a standalone attack function that will calculate the hit damage of the current pokemon, and also take that amount off of the opponent. We can now reuse the pokemonOneAttack and pokemonTwoAttack functions whenever applicable.

Hackerman

The Quick Cheat Sheet

Method Executes immediately? Arguments
call Yes Comma separated
apply Yes Array
bind No (returns new function) Comma separated

Related Posts

Comments