March 21, 2023

Control the function internals with callbacks

There are many uses for callbacks in JavaScript. But the one I really like—and not often talked about—is modifying the behavior of some internal parts of that function.

Let me show you an example.

Example

Let’s say you have a function that fetches and returns some post data.

function getPostById(id) {
  // I'm going to return a literal object here,
  // but imagine it's fetching the post from somewhere
  return {
    title: 'Post Title',
    date: new Date().toString(),
    tags: ['tag1', 'tag2']
  }
}

I’m going to focus on the date field for this example.

The date returned here is formatted using the toString method. If I want to change it to a different format, I have to parse that string into a date object, and then format it however I want.

But wouldn’t it be nice if I can specify the formatting code directly in the function without modifying the function code?

A great thing about JavaScript is that it has first-class functions. This means I can pass functions as values to another functions—we call them callbacks.

So, I can modify the function above to move the formatting code into a callback instead of hardcoding it in the body of the function.

function getPostById(id, fnDateFormatter = (date) => date.toString()) {
  return {
    title: 'Post Title',
    date: fnDateFormatter(new Date()),
    tags: ['tag1', 'tag2']
  }
}

If you run the code above, it will work exactly as the previous one. The difference here is that I format new Date() using the fnDateFormatter callback. Also note how I can specify a default callback in the parameters directly—isn’t JavaScript great?

Because fnDateFormatter is a parameter that accepts a function as a value, I can pass it any other function I want when calling it.

function myDateFormatter(date) {
  return date.toLocaleDateString('en-us', {
    weekday: 'long',
    year: 'numeric',
    month: 'short',
    day: 'numeric'
  })
}

const testPostWithDefaultFormatter = getPostById(1)
const testPostWithMyFormatter = getPostById(1, myDateFormatter)

I called the function twice: one with the default formatter, and one with a custom formatter. Note how I didn’t need to touch the original function code in either one.

Stay up-to-date on the latest projects and articles from me