Functions — the Building Blocks
The single most important concept in programming — giving a name to a piece of work, and reusing it.
If there is one concept in this whole course you should take the time to truly understand, it is functions. Everything else — data structures, classes, asynchronous programming, frameworks — is built on top of functions. They are the atom of programming.
What a function is
A function is a named, reusable piece of code that takes some inputs (arguments) and produces an output (a return value). You define it once. You call it many times.
That picture is the entire mental model. Inputs in, work happens, output out.
Declaring a function
The classic syntax:
function name(parameter1, parameter2) {
// body
return someValue;
}A real example:
Notice four things:
- The declaration is a recipe — it does not execute the body yet.
- A call like
double(3)executes the body, withnbound to3. - The function does its work and
returns a value. - The caller can then use that value.
If a function has no return (or return with nothing after it),
the result is undefined.
Why functions matter
It's tempting to write your whole program as one long script. For twenty lines, that's fine. For two hundred, it becomes a maze. The moment you find yourself copying-and-pasting a chunk of code with small tweaks, you should be writing a function instead.
Functions give you three huge benefits:
- Reuse. Write it once, use it everywhere.
- Naming. A well-named function is documentation.
tip()is easier to read than the formula inside it. - Isolation. What happens inside a function stays mostly inside it. You can think about the function on its own without reading the whole program.
Compare these two equivalent programs:
Both programs produce the same output. One is a maintenance nightmare; the other is a pleasure. The difference is just one function.
Function expressions and arrow functions
JavaScript has more than one syntax for defining functions. They all produce the same kind of value.
Function declaration
function add(a, b) {
return a + b;
}Function expression
A function can also appear as a value on the right-hand side of an assignment:
const add = function (a, b) {
return a + b;
};Arrow function
The most modern, compact syntax. Especially common for short callbacks:
const add = (a, b) => a + b;Arrow functions have a few useful shorthand rules:
- If there is exactly one parameter, the parentheses are optional:
n => n * 2. - If the body is a single expression, the
{}andreturnare optional:n => n * 2. - For a multi-line body, use
{}and an explicitreturnas normal:(n) => { console.log(n); return n * 2; }.
(There are a couple of subtle differences between regular
functions and arrow functions — chiefly around the this
keyword. We will look at this later. For now, treat them as
near-interchangeable.)
Functions are first-class values
This is the deep idea borrowed from Scheme back in 1995, and it is the secret weapon of modern JavaScript.
In JavaScript, functions are values. You can put them in variables, pass them to other functions, return them from functions, and store them in arrays and objects — exactly like numbers and strings.
If this feels like magic, that's normal — and important. We will return to it in the closures chapter.
Pure functions and side effects
A pure function has two properties:
- Given the same inputs, it always returns the same output.
- It does not affect anything outside itself — no printing, no variable changes, no network calls, no file writes.
A function with side effects does some kind of work the outside world can observe: printing, writing files, modifying a shared variable.
Pure functions are easier to think about, easier to test, and easier to reuse. Side effects are sometimes necessary — eventually you do want output and persistence — but the goal of a good design is to keep them in well-marked, predictable places.
Whenever you can, write pure functions and put the side effects
on the edges (a single function that calls console.log, a
single place that touches the database). This single discipline
will, more than almost anything else, make your code
maintainable.
Reading the call stack
Every time you call a function, the runtime pushes a new entry onto its call stack. When the function returns, the entry is popped off. This is how the runtime always knows "where to return to".
In a simple program:
function bigName(name) {
return name.toUpperCase();
}
function greet(name) {
const big = bigName(name); // push bigName onto the stack
return "Hello, " + big; // bigName returns; pop it off
}
console.log(greet("Ada")); // push greet onto the stack
// (greet calls bigName inside)At the moment bigName is running, the call stack looks like:
[ bigName ] <- currently running
[ greet ]
[ console.log ] (well, the runtime's outer frame)When bigName returns, it is removed, and we continue running
greet.
You will see the call stack again when we discuss debugging — most error messages include a stack trace that lists every function that was in progress when the error happened. Learning to read that trace is a superpower.
A multi-file functions example
Real-world programs split functions across files. Each file exports the functions it owns; other files import them. Here is a small two-file example that does exactly that.
bill.js is a small module — a collection of related
functions, exported for use by other files. index.js is the
driver — it imports those functions and uses them. We will see
this pattern many more times.
Challenge
Define a function bmi(weightKg, heightM) that returns the Body Mass Index, using the formula:
bmi = weight / (height * height)
Then define a function bmiCategory(bmi) that returns:
"underweight"if bmi < 18.5"normal"if 18.5 ≤ bmi < 25"overweight"if 25 ≤ bmi < 30"obese"if bmi ≥ 30
Which of these statements about JavaScript functions is true and most distinctive of the language?
Functions can only be called once
Functions cannot be assigned to variables
Functions are first-class values: they can be stored in variables, passed as arguments, and returned from other functions
Functions must always be declared before they're called