Computer Science Fundamentals 5: Functions
Introduction
The Problem: Code Repetition
You've written enough code to notice a pattern: sometimes you write the same block of code over and over in different places.
// Calculate area of a rectangle (first room)
const width1 = 10;
const length1 = 15;
const area1 = width1 * length1;
console.log(area1);
// Calculate area of another rectangle (second room)
const width2 = 8;
const length2 = 12;
const area2 = width2 * length2;
console.log(area2);
// Calculate area of yet another rectangle (third room)
const width3 = 20;
const length3 = 5;
const area3 = width3 * length3;
console.log(area3);
There's a better way. Instead of repeating the calculation, you can wrap code into a reusable block and give it a name.
The Solution: Functions
A function is a named block of code that you can run (invoke) as many times as you want, wherever you want.
function calculateArea(width, length) {
return width * length;
}
// Now, one line does the work of three:
const area1 = calculateArea(10, 15); // 150
const area2 = calculateArea(8, 12); // 96
const area3 = calculateArea(20, 5); // 100
Benefits:
- Less code duplication
- Easier to maintain (change the logic in one place)
- More flexibility (different inputs, different outputs)
What You'll Learn Today
- Function syntax: How to declare and invoke functions
- Parameters & arguments: How to pass data into functions
- Return values: How to get results back
- Function patterns: Different combinations of input and output
- Early returns: A clean pattern to avoid
else
Before You Begin
You know arrays, loops, and objects. Functions are the next building block that tie everything together.
Functions: The Machine Analogy
Think of a function like everyday machines: a washing machine, a toaster, or an oven.
The Pattern: Input → Process → Output
Think of a function like everyday machines: a washing machine, a toaster, or an oven. Each one follows the same pattern:
- Input (arguments): What you put in
- Process (function body): The work that happens
- Output (return value): What comes out
Washing Machine analogy:
- Power button:
()— you invoke it by calling the function - Load the clothes: Your arguments — what goes in
- Machine runs: The function body — the work happens inside (you don't see it)
- Clean clothes come out: The return value — the result
// The washing machine
function washClothes(dirtyClothes, detergent) {
// The process happens inside (we don't write it out)
// Assume the machine does its job...
const cleanClothes = "fresh " + dirtyClothes;
return cleanClothes;
}
// Press the power button with your inputs
const result = washClothes("jeans", "soap");
console.log(result); // "fresh jeans"
Toaster analogy:
- Bread goes in (argument)
- Toaster does its thing (function body)
- Toast comes out (return value)
Oven analogy:
- Raw ingredients go in (arguments)
- Oven heats and cooks (function body)
- Baked goods come out (return value)
Function Syntax & Terminology
Basic Declaration
function greet(name) {
return "Hello, " + name + "!";
}
The parts:
function— the keyword that says "I'm declaring a function"greet— the function name (use a verb: save, calculate, check, validate, etc.)(name)— parameters (placeholders for data that will come in){ ... }— the function body (the work that happens inside)return— sends a value back to the caller
Parameters vs Arguments
-
Parameters: Named placeholders in the function definition
function add(x, y) { // x and y are parameters return x + y; } -
Arguments: The actual values you pass when you call the function
const sum = add(5, 3); // 5 and 3 are arguments
Key insight: Parameters are like labels on boxes. When you call the function, you fill those boxes with arguments.
Invoking a Function
The () is the power button. Without it, the function doesn't run:
function greet() {
return "Hello!";
}
greet; // ❌ Just the name, nothing happens
greet(); // ✅ The power button () invokes it, returns "Hello!"
Return Values
The return keyword sends a value back to whoever called the function:
function multiply(a, b) {
const result = a * b;
return result; // Send this back
}
const product = multiply(4, 5);
console.log(product); // 20
Important: Once return runs, the function stops immediately:
function checkAge(age) {
if (age >= 18) {
return "Adult";
}
console.log("This won't print if age >= 18");
return "Minor";
}
console.log(checkAge(25)); // "Adult" — stops at first return
If a function has no explicit return, it returns undefined:
function add(a, b) {
const result = a + b;
// No return here
}
const sum = add(5, 3);
console.log(sum); // undefined
Generally, you want to return a value so the caller can use it. If you just want to do something (like log), you can, but it's often better to return and let the caller decide what to do. In the latter case, this is called a "side effect" — we'll talk about that later.
Function Patterns: Pure Functions
Core Principle: Functions should be pure—they do one job and return a result. The caller decides what to do with that result (log it, render it, save it, etc.).
This keeps functions testable, reusable, and simple.
The General Rule: Takes Input, Returns Output
// Pure function: does one job, returns a result
function double(num) {
return num * 2;
}
// The CALLER decides what to do with the result
const result = double(5);
console.log(result); // Caller logs it
alert(result); // Caller alerts it
return result; // Caller returns it
storeInDatabase(result); // Caller saves it
Why this matters:
- The function is reusable in any context
- It's easy to test (no hidden side effects)
- The function doesn't decide what happens to the result—the caller does
An Exception: No Arguments, Generates a Value
Sometimes a function generates data that doesn't depend on arguments:
function getRandomNumber() {
return Math.floor(Math.random() * 100);
}
// Caller uses the result however they want
const num = getRandomNumber();
console.log(num);
Note: Math is a built-in object in JavaScript. Math.random() generates a decimal between 0 and 1. By multiplying by 100 and using Math.floor() (round down), we get an integer from 0 to 99.
Early Return: Avoiding Nested else
When you have a condition that should stop the function early, use a direct return:
// Without early return (nested)
function validate(age) {
if (age >= 18) {
return "Valid";
} else {
return "Too young";
}
}
// With early return (cleaner)
function validate(age) {
if (age < 18) {
return "Too young"; // Exit early if condition is true
}
return "Valid"; // Only reached if above return didn't run
}
The early return pattern is cleaner because:
- No nested
if/else - Clear: "If this condition, stop and return"
- Easier to read
function processOrder(items) {
// Check invalid conditions early
if (!items || items.length === 0) {
return "No items to process";
}
if (items.length > 100) {
return "Too many items";
}
// If we get here, all checks passed
return "Order processed: " + items.length + " items";
}
Side Effects: A Peek at the Real World
What is a side effect? When a function does something outside of returning a value—like updating the DOM, changing a global variable, or writing to a database.
Pure Function (No Side Effects)
// Pure: takes input, returns output, nothing else
function calculateTax(price) {
return price * 0.08;
}
const tax = calculateTax(100); // 8
This function is clean and testable. It does one job.
Function with Side Effects (Impure)
// Impure: returns a value AND manipulates the DOM
function calculateAndDisplay(price) {
const tax = price * 0.08;
document.getElementById("tax").innerText = tax; // Side effect!
return tax;
}
calculateAndDisplay(100);
This function does two jobs: calculate AND update the page. This makes it harder to test and less reusable.
Note: document.getElementById("tax").innerText will not work in our current environment since we are not running in a browser. This is just an example to illustrate the concept of side effects.
The Better Pattern
When you need to update the DOM (or perform any side effect):
// Pure function: just calculate
function calculateTax(price) {
return price * 0.08;
}
// The caller handles the side effect
const tax = calculateTax(100);
document.getElementById("tax").innerText = tax; // Caller updates the DOM
Why this is better:
- The function is reusable (works in any context: tests, different pages, etc.)
- The caller decides what happens with the result
- Easier to test: you can verify the calculation without needing a DOM
- Clear separation of concerns: calculation vs. DOM updates are separate
You'll learn more about DOM manipulation in upcoming lessons. For now, just remember: write pure functions that return results, and let the caller decide what to do with them.
Checkpoint: Functions in Practice
Write your answers in handwritten notes ✍️.
-
Write a function called
greetPersonthat takes a name as a parameter and returns a greeting string. -
Write a function called
calculateDistancethat takes two arguments (start,end) and returns the distance between them. -
Write a function called
repeatMessagethat takes a message and a count, then returns a string with that message repeated. Example:repeatMessage("Hi ", 3)returns"Hi Hi Hi ". Why is returning a value here better than just logging? -
Explain: Why is this function problematic?
function getAge(name) { const age = 20; } -
Rewrite this function using early return instead of
else:function isEven(num) { if (num % 2 === 0) { return true; } else { return false; } }
Common Gotchas
Missing the Power Button ()
function sayHi() {
console.log("Hi!");
}
sayHi; // Just references the function, doesn't run it
sayHi(); // Actually runs it
Forgetting to Return
function add(a, b) {
const result = a + b;
// Forgot to return! Don't do this.
}
const sum = add(5, 3);
console.log(sum); // undefined (nothing was returned)
The fix: Always return the result. Let the caller decide what to do.
Type Mismatches
Functions expect certain types. If you pass the wrong type, you get unexpected results:
function add(a, b) {
return a + b;
}
add(5, 3); // 8 ✅
add("5", "3"); // "53" (concatenation, not addition)
add(5, "3"); // "53" (JavaScript converts the number to a string)
add("hello", 3); // "hello3" 🤔
If you try to do math on non-numbers, you get NaN (Not a Number):
function multiply(a, b) {
return a * b;
}
multiply(5, 3); // 15
multiply("5", "3"); // 15 (JavaScript is forgiving here)
multiply("hello", 3); // NaN (can't multiply text by a number)
The lesson: Type consistency matters. As you write more functions, you'll learn to validate inputs.
Wrap-Up
Key Takeaways
Functions are pure blocks of code:
- Do one job
- Take input (arguments)
- Return a result
- Let the caller decide what happens next (log it, render it, save it, etc.)
The machine analogy:
- Arguments go in
- Process happens inside (you don't see it)
- Return value comes out
- The user (caller) decides what to do with the output
Syntax matters:
- Function declaration with parameters
- Invoke with
()(the power button) - Return to send a value back
Pure functions are testable:
- No console.log inside functions
- No hidden side effects
- Easy to verify: given input X, does it return Y?
Early return keeps code clean and avoids nested else.
What's Next
You can now create reusable blocks of code. In the next lesson, you'll learn even more powerful function patterns — including how to pass functions into other functions, and how functions can remember data from their surroundings.
Functions are the building blocks of everything that comes next.