--- type: video yt_id: VVU2YVRMdUlfajQtMHdpRFN6bWFQY3RRLlBrM0FvRmdTaVUw videoId: Pk3AoFgSiU0 title: "JavaScript Callback Functions" date: "2022-06-02T15:56:33Z" slug: "javascript-callback-functions" image: name: "javascript-callback-functions.jpg" alt: "JavaScript Callback Functions" width: 1280 height: 720 status: 'published' description: "By the end of this, i'm going to make sure you understand how to use callback functions in JavaScript." tags: ['JavaScript', 'js', 'functional programming'] --- ## Chapters: * 0:00​ Intro * 0:26 Functions * 5:21 Callback Functions * 9:57 forEach * 12:54 Summary ## Functions Review Before we get into callback functions, let's just review functions a little bit first, because you really need a good understanding of functions in order to understand callback functions. So i'm going to make a function called funny that takes a string and logs it to the console in surrounded with laughing emojis so everyone knows the text is funny. ```js function funny(input) { const output = `🀣 ${input} 🀣` console.log(output) } ``` So if you run this function with the string β€œspiders are the only web devs that like bugs”, it outputs with laughing emojis, because it's a hilrious joke. ```js funny("spiders are the only web devs that like bugs") ``` ```shell > 🀣 spiders are the only web devs that like bugs 🀣 ``` `input` contains the value of the text that is passed to the function, output is that text surrounded by laughing emojis, and the function logs it to the console. ## Different ways to create a function I am creating a [function decleration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) here, but I could also create the function using a [function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function) like this: ```js const funny = function(input) { const output = `πŸ’© ${input} πŸ’©` return output } ``` Or using an [arrow function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) like this: ```js // Arrow function expressions const funny = (input) => { const output = `πŸ’© ${input} πŸ’©` return output } ``` For the sake of this video, these are all exuivalent. No difference. In the end you have a variable named `funny` that references a function. So it can be executed using the round brackets. ```js funny("spiders are the only web devs that like bugs") ``` And since functions are first class values, I could even create a second variable that references the same function if I wanted to: ```js const funnyAgain = funny funnyAgain("spiders are the only web devs that like bugs") ``` It's pointless in this case, but something that's **very important** in JavaScript. Functions are first class values, so they can be assigned to a variable and passed around as arguments just like any other value. Anyway, i'm going to go back to the **function decleration** for the rest of this video because I like using the word `function`. This still gives me a variable called `funny` that references the function. ```js function funny(input) { const output = `🀣 ${input} 🀣` console.log(output) } ``` ## Reusable Functions Functions can accept parameters, `funny` accepts `input`, but functions can also return values. So Instead of console logging the output inside the `funny` function, this function can return the output and I can `console.log` it somewhere else. ```js function funny(input) { const output = `🀣 ${input} 🀣` return output } const message = funny("spiders are the only web devs that like bugs") console.log(message) ``` And this can be nice because it makes the function more _generic_ and _reusable_. Before this refactor, `funny` could only be used to log text to the console; now I can choose to log the output to the console or do something else like add the new string to an array or display it on a web page or pretty much anything. `funny` is now more **reusable**. But all functions don't need to be generic and reusable like this. I will choose to put this new chunk of code into a function called `funnySpiderJoke` to clean things up a bit: ```js function funny(input) { const output = `🀣 ${input} 🀣` return output } function funnySpiderJoke() { const message = poop("spiders are the only web devs that like bugs") console.log(message) } funnySpiderJoke() ``` This gives my chunk of code a name and it makes it a bit cleaner if I want to do something like execute that logic multiple times. Let's say 5: ```js for (let i = 0; i < 5; i++) { funnySpiderJoke() } ``` `funny` is a very generic function, the output will always change based on the input, and I can use the output however I want. `funnySpiderJoke` is a specific function, it will always do the same thing no matter what. Both are functions and both are good. Now I could wrap this new chunk of code into a function as well: ```js function funny(input) { const output = `🀣 ${input} 🀣` return output } function funnySpiderJoke() { const message = poop("spiders are the only web devs that like bugs") console.log(message) } function funnySpiderJokeFiveTimes() { for (let i = 0; i < 5; i++) { funnySpiderJoke() } } funnySpiderJokeFiveTimes() ``` ```shell > 🀣 spiders are the only web devs that like bugs 🀣 > 🀣 spiders are the only web devs that like bugs 🀣 > 🀣 spiders are the only web devs that like bugs 🀣 > 🀣 spiders are the only web devs that like bugs 🀣 > 🀣 spiders are the only web devs that like bugs 🀣 ``` ## Callback Functions `funnySpiderJokeFiveTimes` is a very specific function that will always print out that joke to the console 5 times. But it might be nice to make this function a little bit more generic and reusable. For example, instead of always printing this joke 5 times, I might want to be able to change that number to print it once or twice or a thousand times. So instead of always doing this 5 times, let's change this to be a paramter. ```js function funnySpiderJokeSomeTimes(times) { for (let i = 0; i < times; i++) { funnySpiderJoke() } } const t = 2 funnySpiderJokeSomeTimes(t) ``` Anytime I call the `funnySpiderJokeSomeTimes` function, I can specify how many times this function should print the joke. I can go one step further and make this even more generic by passing in the `funnySpiderJoke` function as a paramter as well. ```js function doSomethingSomeTimes(times, callback) { for (let i = 0; i < times; i++) { callback() } } const t = 2 doSomethingSomeTimes(t, funnySpiderJoke) ``` Remember that functions can be passed to another function just like a number or any other value in JavaScript can be passed to a function. The `times` parameter is a number and it's used instead of the hard coded number 5. The `callback` parameter is a function so we call it with `()` because that's what we do with functions. In this example, `times` is `2` and `callback` is `funnySpiderJoke`, but these could be any number or function. `doSomethingSomeTimes` will work with any number and any function. A callback function is a function passed into another function as an argument, which is then invoked by that function. So any function that is passed into `doSomethingSomeTimes` is a callback function since it's passed into `doSomethingSomeTimes` as an argument and `doSomethingSomeTimes` is now responsible for invoking it using the `()`. This is kind of amazing, because it allows us to create these much more reusable functions by allowing the _specific_ logic to be passed into a function as a function. It makes our code more flexible and reusable. Notice that I am not calling the `funnySpiderJoke` function. I am just passing it in as a paramter. ```js // Not This doSomethingSomeTimes(t, funnySpiderJoke()) // This doSomethingSomeTimes(t, funnySpiderJoke) ``` I don't want to invoke the `funnySpiderJoke` function. I want `doSomethingSomeTimes` to invoke it some number of times. If I invoke the function, the logic will be executed just once, the one time I call the function, and I will be passing the return value of the function to the next function. I don't want that, I want to pass the actual function to `doSomethingSomeTimes`. ## Anonymous Functions Instead of creating a new variable `t` to hold the number 2, I would probably just pass the number 2 in directly like this: ```js function doSomethingSomeTimes(times, callback) { for (let i = 0; i < times; i++) { callback() } } doSomethingSomeTimes(2, funnySpiderJoke) ``` It's also very likely that I'll want to pass in a function as a paramter, but I don't want to create a new variable to hold the function. I want to pass in the function directly. I can do this with an anonymous function. ```js function doSomethingSomeTimes(times, callback) { for (let i = 0; i < times; i++) { callback() } } doSomethingSomeTimes(2, function() { console.log("a new function") }) ``` This will just print out `"a new function"` 2 times to the console. But it demonstrates that I can create the function without creating a new variable for it. I just create it when I call the `doSomethingSomeTimes` function. And in modern JavaScript, it has become more common to use an arrow function for all callback functions. ```js doSomethingSomeTimes(2, () => { console.log("a new function") }) ``` In this example, the outcome will be identical, but in sometimes the outcome will be different if you use an arrow function. I won't get into that in this video, but check the video description for more videos on JavaScript. Just to recap, I can pass in a function as a paramter to a second function and that second function is now responsible for calling the first function. The first function is now the callback function. This makes the code much more reusable and flexible. ## Passing Values to Callbacks Let's take this one step further. We know that we can pass a value to a function, that was the first example in this post. But what if we want to pass a value to a function that is a callback function? ```js function doSomethingSomeTimes(times, callback) { for (let i = 0; i < times; i++) { callback(i) } } ``` This is the same code as before, but now I am passing in the value of `i` to the callback function. So each time the callback function is called, it will get the value of `i` as a paramter which the callback function could choose to use. ```js doSomethingSomeTimes(5, (i) => { console.log("a new function", i) }) ``` This will now print out `"a new function"` with the value of `i` 5 times to the console: ```git > a new function 0 > a new function 1 > a new function 2 > a new function 3 > a new function 4 ``` ## Real Examples Let's look at a more practical example, the `forEach` function. If we were to write `forEach` from scratch, it might look a little something like this: ```js function forEach(array, callback) { for (let i = 0; i < array.length; i++) { callback(array[i]) } } ``` If we call `forEach` and pass in an `array` and a `callback` function, it will run the callback function for each item in the array and pass in each item to the callback function. ```js forEach(["πŸ€—", "πŸ†", "πŸ‘"], (item) => { console.log(item) }) ``` ```shell > πŸ€— > πŸ† > πŸ‘ ``` `forEach` is a very useful function and it's very reusable. It works with any array and any function, and it's so useful that it's build into JavaScript as a method on the `Array` object. ```js ["πŸ€—", "πŸ†", "πŸ‘"].forEach((item) => { console.log(item) }) ``` And callback functions get more and more useful as we go. Using a callback function with the `map` method allows us to create a brand new array based on the original array. ```js const newArray = ["πŸ€—", "πŸ†", "πŸ‘"].map((item) => { return item+item }) > ["πŸ€—πŸ€—", "πŸ†πŸ†", "πŸ‘πŸ‘"] ``` And there are many many more times when callback functions will come up in JavaScript. ## Summary Using callback functions is a great way to make code more flexible and reusable and it's completely unavoidable in JavaScript. Not just because it's a really useful tool, but because sometimes we can't avoid them. When we are dealing with asynchronous code, we often have to use callback functions. And before async/await, we always had to use callback functions to handle asynchronous code. But that's a topic for another post.