Functions
A function is a recipe card. Write the steps once, then cook it whenever you like, with whatever ingredients you have.
Look back at the code you've written so far. A lot of it runs once, top to bottom, and that's it. But real pages do the same jobs again and again: format a price, check an email address, update a cart count. Copying the same lines into every place you need them would be a nightmare to maintain. Change the logic once and you'd have to find every copy.
Functions solve that. You write a set of steps once, give it a name, and run it whenever you want.
A recipe card
Picture a recipe card in a kitchen drawer: "Toast. 1. Put bread in the toaster. 2. Wait until golden. 3. Butter it." The card doesn't make toast by sitting in the drawer. You have to take it out and follow it.
// Writing the recipe card (declaring the function)
function makeToast() {
console.log('Put bread in the toaster.');
console.log('Wait until golden.');
console.log('Butter it.');
}
// Following the recipe (calling the function)
makeToast();
makeToast(); // and again, whenever you likefunctionsays "I'm writing a recipe card."makeToastis its name.- The parentheses
()will hold ingredients, in a moment. - The curly braces hold the steps.
Writing the function doesn't run it. The steps only happen when you call it by writing its name followed by parentheses: makeToast(). Forgetting the parentheses is a classic slip: makeToast on its own just refers to the recipe card without following it.
Ingredients: parameters
A toast recipe that only ever makes white bread isn't very useful. Recipes have ingredients you can swap:
function makeToast(bread, topping) {
console.log(`Toasting ${bread}, topped with ${topping}.`);
}
makeToast('sourdough', 'butter');
makeToast('rye', 'jam');breadandtoppingare parameters: blank spaces in the recipe, waiting to be filled.'sourdough'and'butter'are arguments: the actual ingredients you hand over when you call it.
Arguments are matched to parameters by position: first to first, second to second. Swap them and you'll get jam toasted and topped with rye.
Getting something back: return
So far, our functions only do things (print to the console). Often you want a function to work something out and hand you the answer, like a calculator:
function totalPrice(price, quantity) {
return price * quantity;
}
const cost = totalPrice(4.5, 3);
console.log(cost); // 13.5return sends a value back to wherever the function was called. totalPrice(4.5, 3) gets replaced by its answer, 13.5, which then goes into the cost jar.
Two things to know about return:
- It ends the function immediately. Any lines after a
returnin the same block never run. - A function without a
returnstill gives something back:undefined. If you ever seeundefinedwhere you expected an answer, check for a missingreturn.
function totalPriceBroken(price, quantity) {
price * quantity; // calculated... and thrown away
}
console.log(totalPriceBroken(4.5, 3)); // undefinedreturn also pairs nicely with if for handling special cases first:
function shippingCost(total) {
if (total >= 50) {
return 0; // free shipping, and we're done
}
return 5;
}This pattern, called an early return, keeps functions flat and easy to read.
Default values
What if someone forgets an ingredient?
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet()); // 'Hello, undefined!'A missing argument becomes undefined. You can give a parameter a default that's used whenever the argument is missing:
function greet(name = 'friend') {
return `Hello, ${name}!`;
}
console.log(greet()); // 'Hello, friend!'
console.log(greet('Maria')); // 'Hello, Maria!'Functions are values too
Here's an idea that will matter more and more. A function is a value, just like a number or a string, so you can store it in a variable:
const makeCoffee = function () {
console.log('Brewing coffee...');
};
makeCoffee();This is called a function expression. It works almost exactly like the function makeCoffee() {} version. The main difference is that a declared function can be called from lines above where it's written, because JavaScript reads all function declarations first. A function stored in a const can't be used until that line has run.
You'll use "functions as values" constantly: handing a function to a button so it runs on click, or to a list so it runs for every item. The next lesson, Arrow Functions and Callbacks, is all about that.
Naming functions well
Functions do things, so name them with a verb: calculateTotal, showMenu, formatPrice, isOpen. A function name that starts with is, has, or can promises to return true or false.
And keep each function focused on one job. If you find yourself naming one validateFormAndSendEmailAndUpdatePage, that's three functions pretending to be one. Small functions are easier to read, test, and reuse.
Try it
HTML
JavaScript
Preview
Console
Nothing logged yet. Anything you pass to console.log() shows up here.
(toFixed(2) is a built-in number tool that rounds to two decimal places and gives you back a string, handy for prices while you're learning. Real shops use JavaScript's built-in formatter, which also adds the currency symbol, thousands separators, and each country's own conventions: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(1234.5) gives '$1,234.50'.)
Try it yourself
- Change the number of breads so the subtotal goes over $50. Does the shipping become free?
- Write a function called
applyDiscount(total, percent)that returns the total with the discount taken off. Use it on the final total. - Remove
returnfromtotalPrice(keep the calculation). What happens to every number in the console?
Check your understanding
Up next
You've seen that functions are values you can pass around. Next, you'll learn the short, modern way to write them, and why handing one function to another is such a big deal. That's Arrow Functions and Callbacks.
