Arrow Functions and Callbacks
Sometimes you don't cook the recipe yourself. You hand the card to someone else and say, "Make this when it's time."
In Functions, you learned that functions are values, like numbers and strings. You can put one in a variable. This lesson is about the two things that idea unlocks: a shorter way to write functions, and the ability to hand a function to another function. That second idea runs through almost everything you'll do with JavaScript on the web.
Arrow functions: the short form
Here's a regular function expression:
const double = function (number) {
return number * 2;
};And the same thing as an arrow function:
const double = (number) => {
return number * 2;
};The word function is gone, and an arrow => sits between the parameters and the body. Read it as "number goes to number times two."
It gets shorter still. When the body is a single expression that you want to return, you can drop the braces and the return:
const double = (number) => number * 2;That's called an implicit return: the value after the arrow is returned automatically. A few more shapes you'll see:
const sayHi = () => console.log('Hi!'); // no parameters: empty ()
const square = n => n * n; // one parameter: () are optional
const add = (a, b) => a + b; // two or more: () requiredThis book always writes the parentheses, even for one parameter, because it's consistent and it makes adding a second parameter later painless.
The two classic arrow traps
Trap 1: braces turn off the implicit return.
const double = (number) => { number * 2 };
console.log(double(4)); // undefinedAs soon as you add curly braces, it's a normal block again, and you need return. This one catches everyone.
Trap 2: returning an object. Curly braces after the arrow are read as a block, not an object. Wrap the object in parentheses:
const makeOrder = (bread) => ({ bread: bread, quantity: 1 });You'll meet objects properly in Objects. Just remember the parentheses when you get there.
Callbacks: handing over the recipe
Now the big idea. Imagine you're leaving a note for a babysitter: "When the timer goes off, take the cookies out of the oven." You're not taking the cookies out yourself. You're handing over instructions to be followed later, by someone else, at the right moment.
A callback is a function you pass to another function, so that function can call it when the time is right.
You've already seen one in the HTML and CSS tracks, without the name:
const button = document.querySelector('button');
button.addEventListener('click', () => {
console.log('Clicked!');
});You don't call that arrow function yourself. You hand it to addEventListener, which calls it every time the button is clicked. That's a callback.
Callbacks you'll use constantly
Waiting: setTimeout runs a callback after a delay, in milliseconds.
setTimeout(() => {
console.log('Your bread is ready!');
}, 2000); // after 2 secondsGoing through a list: forEach runs a callback once for every item.
const breads = ['Sourdough', 'Rye', 'Focaccia'];
breads.forEach((bread) => {
console.log(`Fresh today: ${bread}`);
});Sorting: sort uses a callback to decide which of two items comes first.
const prices = [12, 4, 30, 9];
prices.sort((a, b) => a - b);
console.log(prices); // [4, 9, 12, 30]The callback gets two items, a and b. Return a negative number to put a first, a positive number to put b first, or zero to keep them as they are. a - b does exactly that for numbers, smallest first. (b - a sorts largest first.)
And here's a real gotcha: without a callback, sort compares everything as text, like dictionary order:
console.log([10, 9, 1].sort()); // [1, 10, 9]"10" comes before "9" in the dictionary, because "1" comes before "9". Always pass a compare function when sorting numbers.
Passing a function, not calling it
When you hand over a callback, pass the function itself. Don't call it:
function announce() {
console.log('Fresh batch out of the oven!');
}
setTimeout(announce, 1000); // right: hands over the recipe
setTimeout(announce(), 1000); // wrong: cooks it right now, hands over the resultWith the parentheses, announce() runs immediately and its result (undefined) is what gets handed to setTimeout. No parentheses means "here's the recipe card, call it when it's time."
When not to use an arrow
Arrow functions are the right choice for almost every callback. There's one important difference from regular functions, involving a special word called this, that you'll learn about in this and Classes. Until then, a simple rule: use arrow functions for callbacks and small helpers, and regular function declarations for your main, named functions.
Try it
HTML
JavaScript
Preview
Console
Nothing logged yet. Anything you pass to console.log() shows up here.
(The [...prices] makes a copy of the list first, so both sort lines start from the original order. You'll learn that ... trick in Destructuring and Spread.)
Try it yourself
- Press the button and watch the status change after two seconds. Then change the delay to 500.
- Change the numeric sort so it puts the largest price first.
- Write an arrow function
const triple = (number) => number * 3;and logtriple(7). Then add curly braces around the body without addingreturn, and see what it logs.
Check your understanding
Up next
Your functions are getting powerful. But where can each variable actually be seen from, and how can a function remember something after it's finished running? That's Scope and Closures.
