Frontend Master

JavaScript Curriculum

Don't Repeat Yourself
+35 XP

Don't Repeat Yourself

easy
~18 min·35 XP

The Nexus dashboard shows a price on 14 different screens. Right now \"$\" is hardcoded 14 times. When the product team says \"we're going international — support GBP too\", you'd have to edit 14 places and hope you don't miss one. There's a better way: write the formatting logic once, name it, and call it wherever you need it.

The copy-paste trap

You write "$" + price.toFixed(2) once. It works. Two weeks later you need it on another screen — paste. Then another — paste. Then the product team wants £ support. You search through your entire codebase trying to find every place you pasted it.

This is the copy-paste trap. The fix is a function.

A function is a named, reusable block of code. Write the logic once. Call it by name wherever you need it. Change it in one place — it updates everywhere.


The anatomy of a function

Every part of a function has a job. Click each highlighted section to see what it does:

function anatomy — click any highlighted part
functionformatPrice(amount, currency) {
const symbol = currency === "USD" ? "$" : "£"
return`${symbol}${amount.toFixed(2)}`
}

← click any coloured part to learn what it does

🧠A function is a recipe
A recipe has a name ("Pasta Carbonara"), ingredients it needs (eggs, pasta, cheese), and steps to follow. A function has a name, parameters it accepts, and a body that does the work. Calling a function is like saying "make this recipe with these ingredients."

Parameters and arguments

Parameters are the named placeholders you define in the function signature. Arguments are the actual values you pass in when calling it.

js
// "amount" and "currency" are PARAMETERS function formatPrice(amount, currency) { return `${currency}${amount.toFixed(2)}` } // 9.5 and "$" are ARGUMENTS formatPrice(9.5, "$")

You can have zero parameters, one, or many — separated by commas.

js
function greet() { return "Hello!" } // 0 params function double(n) { return n * 2 } // 1 param function add(a, b) { return a + b } // 2 params function clamp(n, min, max) { return Math.min(Math.max(n, min), max) } // 3

How a function call actually works

Watch the flow: call site → function body → return value travels back:

function call flow
amount =
formatPrice(42.5)

1. call site

JavaScript sees the function call with your argument

2. body runs

The code inside the function executes

3. return

The return value travels back to the call site

function formatPrice(amount) {
const symbol = "$"
return`${symbol}${amount.toFixed(2)}`
}

Three things happen every time you call a function. First JavaScript sees the call and packages up your argument. Then it jumps into the function body and runs the code. Finally return sends a value back — and execution resumes exactly where it left off.


The return statement

return does two things: it sends a value back to the caller, and it exits the function immediately. Nothing after return runs.

js
function getDiscount(isVip) { if (isVip) { return 0.20 // ← exits here for VIP users } return 0 // ← exits here for everyone else } const discount = getDiscount(true) // 0.20

A function without a return statement (or one that just says return) gives back undefined.

💡Return early to avoid nesting
Instead of nesting your happy path inside an if block, return early for the error case. Your code reads top-to-bottom without deep indentation.
js
// ✗ nested — harder to follow function processUser(user) { if (user) { if (user.isActive) { return `Processing ${user.name}` } } return "Invalid" } // ✓ early returns — reads clearly function processUser(user) { if (!user) return "Invalid" if (!user.isActive) return "Invalid" return `Processing ${user.name}` }

Arrow functions — the modern syntax

ES6 (2015) introduced a shorter syntax for functions. Today you'll see this everywhere in modern JavaScript codebases.

same function — four ways to write it
function double(n) {
return n * 2
}
function keyword

The classic syntax. Works everywhere. Hoisted — can be called before it is defined.

All four versions do exactly the same thingdouble(5) returns 10 in every case.

The implicit-return one-liner is extremely common for small transformations — especially when you'll learn about array methods in the next lesson.


Default parameters

You can give parameters a fallback value that's used when the caller doesn't provide one:

js
function greet(name = "stranger") { return `Hello, ${name}!` } greet("Alex") // "Hello, Alex!" greet() // "Hello, stranger!" ← default used

This is much cleaner than checking if (!name) inside the function body.


Building your formatPrice function

Here's what the complete solution looks like — step by step:

js
function formatPrice(amount, currency) { // 1. Decide the symbol based on currency let symbol = "$" if (currency === "GBP") symbol = "£" if (currency === "EUR") symbol = "€" // 2. Format the number to 2 decimal places const formatted = amount.toFixed(2) // 3. Return the combined string return `${symbol}${formatted}` } console.log(formatPrice(9.5, "USD")) // "$9.50" console.log(formatPrice(49, "GBP")) // "£49.00" console.log(formatPrice(100, "EUR")) // "€100.00"

Now if the product team adds JPY next month, you change exactly one function and every screen updates.

✗ copy-paste
✓ DRY — one source of truth

Challenge

Write a function called formatPrice(amount, currency) that returns a formatted price string. If currency is \"USD\" prefix with \"$\". If currency is \"GBP\" prefix with \"£\". If currency is \"EUR\" prefix with \"€\". Always show exactly 2 decimal places (use .toFixed(2)). Log formatPrice(9.5, \"USD\"), formatPrice(49, \"GBP\"), and formatPrice(100, \"EUR\").

functionsparametersreturnarrow-functionsDRYreusability
Don't Repeat Yourself | Nexus Learn