Hello, world!

My name is Justin Juno. I'm an infinitely curious and optimistic software developer seeking career opportunities. Welcome to my corner of the internet.

Explicit Binding and Pizza

Posted on 08-23-2020

JavaScript methods .call, .apply, and .bind allow us to immediately invoke a function or return a new function (that we can invoke later) with a specified context.

Getting Started

We will start with a customer object and an orderPizza function. Since our function isn't a method on our customer object, we will need to help our program understand what this is referring to in our function.

function orderPizza() {
	console.log(`${this.name} just ordered a pizza!`)
}

const customer = {
	name: "Justin Juno",
	phone: "123-456-7890"
}

Your first instinct might be to pass our customer object into the orderPizza function, but the name will still return undefined.

Why? Because our function needs context.

This is where .call, .apply, and .bind come into play. For our customer to place an order in our program successfully, we will need to invoke the function using one of the aforementioned methods.

Using the .call method

function orderPizza() {
	console.log(`${this.name} just ordered a pizza!`)
}

const customer = {
	name: "Justin Juno",
	phone: "123-456-7890"
}

orderPizza.call(customer)

Like any function or method in JavaScript, we can pass arguments to it. When using .call, .apply, or .bind the first argument is always the context. In other words, what this is referring to in the function we are invoking. In this example, that would be our customer, Justin Juno.

So what happens, if we need to pass additional arguments to our function, like toppings? We just pass them after our context. One downside to .call is that we have to pass all of our additional arguments individually.

function orderPizza(topOne, topTwo) {
	console.log(`${this.name} just ordered a pizza with: ${topOne} ${topTwo}`)
}

const customer = {
	name: "Justin Juno",
	phone: "123-456-7890"
}

orderPizza.call(customer, 'cheese', 'hamburger')

Using the .apply method

This is where .apply comes in. It works just the same as .call, but instead of passing our additional arguments individually, we can pass them as an array. Making it a much better solution when multiple arguments are needed.

function orderPizza(topOne, topTwo) {
	console.log(`${this.name} just ordered a pizza with: ${topOne} ${topTwo}`)
}

const customer = {
	name: "Justin Juno",
	phone: "123-456-7890",
  	toppings: ['cheese', 'hamburger']
}

orderPizza.apply(customer, customer.toppings)

Using the .bind method

This brings us to .bind. It also works just the same as .call. However, instead of immediately invoking the function, it returns a new function that we can invoke later. This gives us a lot of flexibility because we can choose when, where, and how we would like to invoke the function.

function orderPizza(topOne, topTwo) {
	console.log(`${this.name} just ordered a pizza with: ${topOne} ${topTwo}`)
}

const customer = {
	name: "Justin Juno",
	phone: "123-456-7890"
}

const futureOrder = orderPizza.bind(customer, 'cheese', 'hamburger')

setTimeout(() => futureOrder(), 1000);

In this example, I've bound our orderPizza function to a new function called futureOrder. Then added a setTimeout function that will invoke our futureOrder function after 1 second.


Wrapping Up

I hope these tasty examples of .call, .apply, and .bind satisfied your hunger for knowledge . . . and cheese-y puns.

"If you roll back the clock far enough, we're all just chimps. Some of us just learned how to clickety-clack on a keyboard."

Ian Ramzy