JavaScript Callbacks

Objectives

  1. Explain what a callback is
  2. Explain how callbacks are used in JavaScript
  3. Practice writing functions that take callbacks

Introduction

When I was your age, I had a boat.

Boat

It was not a fancy boat or a particularly nice boat, but it was my boat.

Boats, as you know, have many moving parts. And these parts need to be cleaned.

Now, I could have cleaned every part separately, iterating through the piles of barnacle-encrusted tools one by one, preparing to clean each individual piece with a bit of a care.

Or I could get a bit smarter about it. I could prepare once for each group of related items, so that I wouldn't have to prepare to clean each item individually. In code, that might look like:

function clean(item) {
  console.log(`I just cleaned a ${item}`)
}

var nails = ["rusty nail", "rusty nail", "bent nail", "clean nail"]

for (var i = 0; i < nails.length; i++) {
  clean(nails[i])
}

var planks = ["splintered plank", "straight plank", "bent plank"]

for (var i = 0; i < planks.length; i++) {
  clean(planks[i])
}

console.log('done!')

And so on and so forth. Well now, this wasn't so bad, but I noticed that I was preparing to clean everything — and cleaning everything, really — in the same way. What if I could just group all of the things that I needed to clean, and prep for the cleaning once?

function groupAndClean(items, cleaningMethod, done) {
  for (var i = 0; i < items.length; i++) {
    cleaningMethod(items[i])
  }

  done()
}

groupAndClean(nails.concat(planks), clean, function() {
  console.log('Whew, that was a lot of work!')
})

So went the days of my youth, when I learned to pass functions as arguments to other functions.

And my boat was cleaner for it.

Functions as arguments

In JavaScript, we have the ability to pass functions as arguments. This makes it really easy to abstract functionality out of our programs, making the programs easier to reason about by breaking them into smaller chunks.

For example, let's say we have a function that lets us do anything we want to the number 5 (follow along in the browser's console!):

function doTo5(anything) {
  return anything(5)
}

Well, let's try it out. Can we divide with it?

function divide10ByN(n) {
  return 10 / n
}

doTo5(divide10ByN) // 2

Cool, cool. Can we append it to a string?

function appendToHello(s) {
  return `Hello, ${s}!`
}

doTo5(appendToHello) // 'Hello, 5!'

Some things to note:

  • neither divide10ByN() nor appendToHello() knows that it's going to receive 5 specifically — these functions only know that they're going to receive an argument. They're very generic.

  • We do not call divide10ByN or appendToHello when we pass them as functions to doTo5() — that is, we pass just their name without any parentheses after it. That's because the calling actually happens inside doTo5(), when doTo5() calls back to the "outside world." Because of this process of calling back, we often call functions that we pass to other functions callbacks.

Other uses for callbacks

Callbacks can also be useful for when we finish an expensive operation and want to return to a previous function's context (similarly to how done() was used in the boat example).

function somethingExpensive(callback) {
  // do something crazy,
  // like fetching a bajillion websites
  // then pass their data to callback:

  // (supposing that we have defined `data`
  // along the way)
  callback(data)
}

Resources

View Javascript Callbacks on Learn.co and start learning to code for free.