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
}

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:

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.