Unit 1 · Module 3
Functions — Reusable Instructions
Write it once, use it everywhere
You now know that variables hold information. But holding information isn't useful if you can't do anything with it. That's where functions come in.
A function is a set of instructions with a name. You write the instructions once, give them a name, and then you can run those instructions whenever you want just by calling the name.
Let's say you're building an intake form. Every time someone submits it, you need to do three things: check that all required fields are filled in, format the phone number so it's consistent, and send the data to the database.
You could write those three steps out every time a form is submitted. But you have multiple forms — the initial intake, the follow-up, the contact update. Are you going to copy-paste those same steps everywhere?
No. You write it once, give it a name, and call it wherever you need it.
A function that handles form submission
function submitForm(formData) {
validateFields(formData)
formatPhoneNumber(formData)
saveToDatabase(formData)
}
Now anywhere in your code, you just write submitForm(formData) and all three
steps happen. One name. Three steps behind it. Every time.
The anatomy of a function
A function has four parts. Each one matters.
A function with all four parts labeled
function calculateTotal(price, quantity) {
let total = price * quantity
return total
} function— a built-in keyword that says "I'm defining a set of instructions"calculateTotal— the name. This is how you call it later. The developer chose this name.(price, quantity)— the parameters (inputs). These are placeholders that say "when you call me, give me these pieces of information and I'll use them." The function doesn't know what the price or quantity is until you actually call it with real values.return total— the output. The function did some work and now it's handing back a result.
When you call it:
Calling the function
let orderTotal = calculateTotal(29.99, 3)
Translation: "Run the calculateTotal instructions. The price is 29.99. The
quantity is 3. Give me back the result." And orderTotal is now a variable
holding 89.97.
Try It: Step Through a Function
Step through this function one line at a time — watch the variables change
The call
Variables in RAM
Nothing yet
Click "Next Step" to start executing the function.
Arrow functions — same thing, different syntax
There are two ways to write a function in JavaScript. They do the same thing.
Way 1: function keyword
function calculateTotal(price, quantity) {
let total = price * quantity
return total
} Way 2: arrow function
const calculateTotal = (price, quantity) => {
let total = price * quantity
return total
}
The arrow function (=>) is the one you see more often in modern code. It
doesn't use the word function at all. Instead it uses const (creating
a named container), the name, an equals sign, the parameters, then a fat arrow
=>, then the instructions in brackets.
Same result. Same behavior. Just different notation. So when you're reading code and you see
const doSomething = () => { ... } — that's a function. It just
doesn't announce itself with the word "function."
Where do functions live?
A function lives in a file. Any other file can import it. Here's a simplified file structure
showing where a submitForm function might live in a real app:
File structure
src/
components/
IntakeForm.tsx — the form component (what the user sees)
FormBuilder.tsx — the reusable form builder
utils/
formHelpers.ts — shared functions like submitForm, validateFields
app/
api/
lead-intake/
route.ts — the API endpoint that receives submitted data submitForm would live in something like formHelpers.ts — a utility
file whose whole job is to hold reusable functions. It doesn't render anything on screen.
It's just a library of instructions other files can pull from.
Then any component that needs it does this:
Importing a function
import { submitForm } from '../utils/formHelpers'
That line says: "Go to that file, find the function called submitForm, and bring
it here so I can use it." Now IntakeForm.tsx can call submitForm().
FormBuilder.tsx can call submitForm(). Any file that imports it
can use it. The function lives in one place, but it's available everywhere that asks for it.
Why do functions exist?
Two things break immediately without them.
First: repetition. Without functions, every time you needed to submit a form, you'd write the validation, formatting, and API call again. That could be 30-40 lines of code. Copied into twelve different places. Now you find a bug in the phone formatting. You have to fix it in all twelve places. Miss one and you have inconsistent behavior. Functions let you fix it in one place and it's fixed everywhere.
Second: readability. Compare these two:
Without functions — you see every step
let subtotal = price * quantity
let tax = subtotal * 0.08
let shipping = subtotal > 50 ? 0 : 5.99
let total = subtotal + tax + shipping With a function — you see the intent
let total = calculateTotal(29.99, 3) The second version tells you what's happening without making you read how. The details are tucked inside the function. You only go look if you need to. Developers call this abstraction — hiding the steps behind a name so you can think at a higher level.
Abstraction layers — functions inside functions
Functions can call other functions. Look at submitForm again:
A function calling other functions
function submitForm(formData) {
validateFields(formData)
formatPhoneNumber(formData)
saveToDatabase(formData)
}
Each of those three lines is calling another function defined somewhere else. If you opened up
validateFields, you'd see the actual step-by-step work:
Inside validateFields
function validateFields(formData) {
if (!formData.firstName) {
throw new Error("First name is required")
}
if (!formData.email) {
throw new Error("Email is required")
}
} That's layers of abstraction:
- Top layer:
submitForm— calls three functions. Reads like a summary: "validate, format, save." - Middle layer:
validateFields— the actual checking logic with real instructions. - Bottom layer: Built-in JavaScript operations like
if,throw, comparison checks — the raw language itself.
This is how real apps are built. You stack named operations on top of each other until the
top level reads almost like English. That's what good code looks like — not because it's fancy,
but because a human can read submitForm and immediately know what happens without
reading 60 lines of detailed logic.