Functions
Package reusable code into named blocks — the building blocks of every JavaScript program.
1. Introduction
A function is a named, reusable block of code. Instead of writing the same logic in ten places, you write it once, give it a name, and call it whenever you need it. Functions are the single most important concept in programming.
Functions enable:
- Reuse — write once, call many times
- Organisation — break a large problem into named, focused pieces
- Testability — test each piece independently
- Abstraction — hide complexity behind a simple name
This lesson covers function declarations, expressions, arrow functions, parameters, return values, and default parameters.
2. Theory
2.1 Function declaration
The classic way to define a function. Function declarations are hoisted — you can call them before they appear in the source code.
// Define the function
function greet(name) {
return 'Hello, ' + name + '!';
}
// Call the function
console.log(greet('Alice')); // 'Hello, Alice!'
console.log(greet('Bob')); // 'Hello, Bob!'
Anatomy:
function— keywordgreet— function name (camelCase)(name)— parameter list (the inputs){ ... }— function bodyreturn— sends a value back to the caller
2.2 Parameters and arguments
- Parameter — the name defined in the function signature:
(name) - Argument — the actual value passed when calling:
greet('Alice')
function add(a, b) { // a and b are parameters
return a + b;
}
add(3, 5); // 3 and 5 are arguments → returns 8
add(10, 20); // 10 and 20 are arguments → returns 30
2.3 The return statement
return sends a value back and immediately exits the function:
function square(n) {
return n * n;
console.log('never reached'); // after return, code stops
}
const result = square(4); // result = 16
// A function without return gives undefined
function doSomething() {
console.log('Side effect');
}
const val = doSomething(); // val is undefined
Functions can have multiple return statements — often used with guard clauses:
function divide(a, b) {
if (b === 0) return null; // guard: cannot divide by zero
return a / b;
}
2.4 Default parameters
Provide a fallback value for a parameter if the caller doesn't pass one:
function greet(name = 'World') {
return `Hello, ${name}!`;
}
console.log(greet('Alice')); // 'Hello, Alice!'
console.log(greet()); // 'Hello, World!' — default used
function createUser(name, role = 'viewer', active = true) {
return { name, role, active };
}
console.log(createUser('Alice')); // { name:'Alice', role:'viewer', active:true }
console.log(createUser('Bob', 'admin')); // { name:'Bob', role:'admin', active:true }
2.5 Function expression
A function assigned to a variable. Not hoisted — must be defined before use.
const multiply = function(a, b) {
return a * b;
};
console.log(multiply(3, 4)); // 12
2.6 Arrow functions (ES6)
A shorter syntax for function expressions. Arrow functions are the modern standard for callbacks and inline functions.
// Arrow function — full form
const add = (a, b) => {
return a + b;
};
// Implicit return — when the body is a single expression
const add2 = (a, b) => a + b;
// Single parameter — parentheses optional
const double = n => n * 2;
// No parameters — parentheses required
const sayHi = () => 'Hello!';
console.log(add(2, 3)); // 5
console.log(double(7)); // 14
console.log(sayHi()); // 'Hello!'
Declaration vs Expression vs Arrow — comparison
| Feature | Declaration | Expression | Arrow |
|---|---|---|---|
| Syntax | function f() {} | const f = function() {} | const f = () => {} |
| Hoisted | Yes | No | No |
Own this | Yes | Yes | No (inherits) |
| Best for | Named, top-level functions | Conditional assignment | Callbacks, short inline functions |
2.7 Calling a function vs referencing it
function greet() { return 'Hello'; }
// Calling — runs the function, gets the return value
console.log(greet()); // 'Hello'
// Referencing — the function itself (not called)
console.log(greet); // ƒ greet() { return 'Hello'; }
// Passing as an argument (callback pattern)
setTimeout(greet, 1000); // calls greet after 1 second
// NOT: setTimeout(greet(), 1000) — that calls it immediately!
2.8 Functions calling other functions
function celsiusToFahrenheit(c) {
return c * 9/5 + 32;
}
function describeTemperature(celsius) {
const f = celsiusToFahrenheit(celsius); // call another function
if (celsius >= 30) return `${celsius}°C (${f}°F) — Hot!`;
if (celsius >= 20) return `${celsius}°C (${f}°F) — Warm.`;
return `${celsius}°C (${f}°F) — Cool.`;
}
console.log(describeTemperature(35)); // '35°C (95°F) — Hot!'
console.log(describeTemperature(22)); // '22°C (71.6°F) — Warm.'
3. Real World Example
// Shopping cart utilities
function formatPrice(amount) {
return '$' + amount.toFixed(2);
}
function calculateTax(price, rate = 0.08) {
return price * rate;
}
function calculateTotal(items) {
let subtotal = 0;
for (const item of items) {
subtotal += item.price * item.quantity;
}
const tax = calculateTax(subtotal);
const shipping = subtotal >= 50 ? 0 : 5.99;
const total = subtotal + tax + shipping;
return { subtotal, tax, shipping, total };
}
const cart = [
{ name: 'Book', price: 12.99, quantity: 2 },
{ name: 'Pen', price: 2.50, quantity: 5 },
];
const summary = calculateTotal(cart);
console.log('Subtotal:', formatPrice(summary.subtotal)); // $38.48
console.log('Tax:', formatPrice(summary.tax)); // $3.08
console.log('Shipping:', formatPrice(summary.shipping)); // $5.99
console.log('Total:', formatPrice(summary.total)); // $47.55
4. Code Example
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Functions Demo</title></head>
<body>
<h1>Temperature Converter</h1>
<input type="number" id="temp-input" placeholder="Temperature">
<select id="unit-select">
<option value="c">Celsius to Fahrenheit</option>
<option value="f">Fahrenheit to Celsius</option>
</select>
<button id="convert-btn">Convert</button>
<p id="result"></p>
<script>
// Pure functions — no side effects, same input → same output
const toFahrenheit = celsius => (celsius * 9 / 5) + 32;
const toCelsius = fahrenheit => (fahrenheit - 32) * 5 / 9;
function formatResult(value, from, to) {
return `${value.toFixed(1)}°${from.toUpperCase()} = ${convert(value, from).toFixed(1)}°${to.toUpperCase()}`;
}
function convert(value, unit) {
return unit === 'c' ? toFahrenheit(value) : toCelsius(value);
}
document.querySelector('#convert-btn').addEventListener('click', () => {
const input = Number(document.querySelector('#temp-input').value);
const unit = document.querySelector('#unit-select').value;
if (isNaN(input)) {
document.querySelector('#result').textContent = 'Please enter a valid number.';
return;
}
const converted = convert(input, unit);
const fromUnit = unit === 'c' ? 'C' : 'F';
const toUnit = unit === 'c' ? 'F' : 'C';
document.querySelector('#result').textContent =
`${input.toFixed(1)}°${fromUnit} = ${converted.toFixed(1)}°${toUnit}`;
});
</script>
</body>
</html>
5. Code Breakdown
Arrow functions as constants
const toFahrenheit = celsius => (celsius * 9 / 5) + 32 — a single-expression arrow function with an implicit return. The parentheses around the expression are optional but improve readability when the formula is complex.
Separation of concerns
Three functions with distinct responsibilities:
toFahrenheit/toCelsius— pure math, no side effectsconvert— chooses which formula to use based on unit- The event handler — reads the DOM, calls convert, updates the DOM
Guard clause in the event handler
if (isNaN(input)) { ...; return; } — if the input is not a valid number, show an error and exit early. The conversion logic below is only reached with valid data.
Ternary for unit labels
unit === 'c' ? 'F' : 'C' — the target unit is the opposite of the selected unit. This avoids a second if/else block.
6. Common Mistakes
Mistake 1 — Calling a function instead of passing it as a callback
// Bad — calls greet immediately and passes its return value (undefined)
btn.addEventListener('click', greet());
// Good — passes the function itself; browser calls it on click
btn.addEventListener('click', greet);
Mistake 2 — Forgetting return
function add(a, b) {
a + b; // calculates but doesn't return anything!
}
console.log(add(2, 3)); // undefined
// Good
function add(a, b) {
return a + b;
}
Mistake 3 — Modifying the parameter name vs using default
// Bad — manual default check
function greet(name) {
if (!name) name = 'World'; // works but verbose
return `Hello, ${name}`;
}
// Good — default parameter
function greet(name = 'World') {
return `Hello, ${name}`;
}
Mistake 4 — Using arrow functions as methods that need this
// Arrow functions don't have their own 'this'
const counter = {
count: 0,
// Bad — 'this' is not the counter object inside arrow
increment: () => { this.count++; }, // this is undefined in strict mode
// Good — use regular function for methods
increment() { this.count++; },
};
Mistake 5 — Giant functions that do too much
A function should do one thing. If you find yourself naming a function loadDataAndValidateAndDisplayAndLogErrors(), split it into smaller focused functions.
7. Best Practices
- One function, one job — functions should do one thing and do it well (Single Responsibility Principle).
- Use descriptive names —
calculateTotal(), notdoStuff(). Verb + noun is a good pattern. - Prefer pure functions where possible — same input always produces same output, no side effects. They are easy to test and reason about.
- Use default parameters instead of if(!param) checks inside the function body.
- Use arrow functions for callbacks and short inline functions, function declarations for named top-level functions.
- Keep functions short — if a function is longer than 20–30 lines, it probably does too much.
- Return early using guard clauses — reduces nesting and makes the happy path clear.
- Avoid side effects in calculation functions — separate "compute" from "display."
8. Practice Exercise
- Write a function
isPrime(n)that returnstrueifnis a prime number. Test it with a loop from 1–20. - Write a function
clamp(value, min, max)that returnsvaluebut clamped betweenminandmax. - Write an arrow function
repeat = (str, n)that returns the string repeated n times:repeat('ha', 3)→'hahaha'. - Write a function
summarise(numbers)that returns an object withmin,max,sum, andaverageof the array. - Rewrite the
summarisefunction using arrow function syntax.
Bonus
- Build a "Password Strength Checker": a function
checkStrength(password)that returns 'Weak', 'Medium', or 'Strong' based on length, and presence of numbers and uppercase letters.
9. Assignment
Build a "Unit Converter" app with multiple conversion types.
- Write separate functions for each conversion:
kmToMiles(km)andmilesToKm(miles)kgToLbs(kg)andlbsToKg(lbs)litresToGallons(l)andgallonsToLitres(g)
- Write a
convert(value, type, direction)function that dispatches to the right sub-function. - Build an HTML form: number input, conversion type selector, direction (to/from), and a Convert button.
- Display the result. Validate input (not empty, is a number, is positive).
- Add default parameter: if no direction is specified, default to the first direction.
Deliverable: One HTML file. All conversion logic in separate, named functions.
10. Interview Questions
- What is the difference between a function declaration and a function expression?
A function declaration is hoisted — it can be called before it appears in the source. A function expression (assigned to a variable) is not hoisted and must be defined before use. - What is an arrow function and how does it differ from a regular function?
Arrow functions have a shorter syntax and do not have their own this binding. They inherit this from the surrounding scope. They cannot be used as constructors. Best used for callbacks and short inline functions. - What does the return statement do?
It sends a value back to the caller and immediately exits the function. A function without a return statement returns undefined. - What is the difference between a parameter and an argument?
A parameter is the name in the function definition (a placeholder). An argument is the actual value passed when calling the function. - What is a pure function?
A function that: 1) given the same inputs, always returns the same output, and 2) has no side effects (doesn't modify external state). Pure functions are easy to test and reason about. - What are default parameters?
Default values assigned to parameters in the function signature. If the caller doesn't pass a value (or passes undefined), the default is used. Example: function greet(name = 'World') {}.
11. Additional Resources
- MDN — Functions guide
- MDN — Arrow function expressions
- javascript.info — Functions
- javascript.info — Arrow functions, the basics
- MDN — Default parameters