Advanced Functions

Functions as First-Class Citizens

This appendix picks up the advanced function concepts from Chapter 5. You’ll see these patterns all over professional code, and they’re worth a proper look once the basics feel comfortable.

Pure Functions: Questions vs. Commands

Functions come in two fundamentally different species. The distinction is subtle, but it matters.

Some functions are really questions. “What is 2 plus 3?” An answer arrives (5), and nothing in the world has changed. Ask the same question tomorrow, and you get the same answer back. These are pure functions.

function add(a, b) {
  return a + b;
}

// Always returns 5. Always. No matter when you call it.
add(2, 3);

Other functions are commands. “Paint that wall blue.” Now something has changed. The wall was one colour, now it’s another, and the question can no more be un-asked than the wet roller can be wrung back into a fresh, sealed tin. These functions have side effects.

let total = 0;

function addToTotal(amount) {
  total = total + amount; // Changes something outside the function!
  return total;
}

addToTotal(5); // Returns 5, but also changes total
addToTotal(5); // Returns 10! Different answer for same input!
Test your ability to identify pure vs impure functions.

Pure functions are predictable and easy to reason about. Like a vending machine: press B4, out comes the same packet of crisps, today and every day. Functions with side effects are trickier. Their behaviour depends on the state of the world around them, and the world has a habit of moving when you weren’t looking.

As a general principle, prefer pure functions where possible. They test more easily, debug more readily, and are easier to understand. But sometimes side effects are unavoidable: printing, saving files, communicating over networks. The skill lies in knowing which variety you’re dealing with.

Functions as Values: A Mind-Bending Concept

Here’s something that may twist your mind: functions are values, just like numbers or strings.

Step through this demonstration to see functions stored in variables.

You can pass a function to another function:

function applyTwice(func, value) {
  return func(func(value));
}

function addOne(n) {
  return n + 1;
}

const result = applyTwice(addOne, 5);
console.log(result); // 7 (5 + 1 = 6, 6 + 1 = 7)

This is “higher-order programming”: functions that operate on other functions. Like teaching someone not just skills, but meta-skills: “Here’s how to apply any skill twice, whatever the skill happens to be.”

JavaScript arrays come with a few built-in higher-order methods that earn their keep:

See how .map() applies a function to every element in an array.
Watch how .filter() keeps only items that pass a test.

If this feels peculiar at first, good. It is peculiar. But it’s also powerful, and with practice it goes the way of riding a bicycle: the wobble disappears and only the speed is left.


Return to Chapter 5 for the core function concepts, or explore both appendices to deepen your understanding of control flow and functional programming patterns.