Phase 2 · Core JavaScriptModule 11~44 min read

Advanced Functions

Treat functions as values with callbacks, higher-order functions, recursion, and composition.

What you'll learn

Because functions are values, JavaScript can express policies as callbacks, build behavior with composition, and solve recursive problems without hard-coding every operation.

By the end of this lesson, you'll be able to:

  • Design higher-order utilities
  • Write safe recursive functions
  • Compose small transformations

Core mental model

Use this decision table as a compact reference. Focus on what each tool means and when it earns its place in production code.

ConceptWhat it meansDecision rule
CallbackBehavior passed into another functionPass policy when the algorithm stays the same
RecursionA function solves a smaller version of its problemRequire a clear base case and decreasing input
CompositionOutput from one function becomes input to anotherCompose pure, single-purpose transformations

Professional workflow

Build the behavior in small, observable steps. Each step should leave something you can inspect or test.

  1. Describe the higher-order function boundary: inputs, outputs, state, timing, and expected failures.
  2. Implement the smallest correct path with names that expose intent.
  3. Add edge cases and failure handling before introducing abstractions.
  4. Verify behavior with realistic data and one deliberately adversarial example.
  5. Refactor only after the observable behavior is protected.

Make behavior observable

Before optimizing or abstracting, make inputs, outputs, state changes, timing, and failure paths visible. JavaScript becomes much easier to reason about when hidden work is exposed.

Guided code lab

Inject a selection policy

The reusable selector does not know what qualifies; the callback owns that decision.

select.js
function select(values, predicate) {
  const result = [];
  for (const value of values) if (predicate(value)) result.push(value);
  return result;
}
console.log(select([3, 8, 11, 14], value => value % 2 === 0));

Recurse through nested data

Each call reduces the problem to child nodes and stops at primitive values.

deep-count.js
function countValues(value) {
  if (!Array.isArray(value)) return 1;
  let total = 0;
  for (const item of value) total += countValues(item);
  return total;
}
console.log(countValues([1, [2, 3], [[4]]]));

Production practice

Contract

Document what the callback receives, returns, and whether call order matters.

Verification

Test empty input, one element, nested input, and a callback that rejects everything.

Operations

Name composed stages so stack traces and metrics remain understandable.

Common failure mode

A higher-order abstraction that hides control flow can be harder to maintain than a direct loop.

Independent workshop

Create a transformation pipeline for product records: validate, normalize, discount, and format.

Your finished workshop must include:

  • At least three pure stages
  • One reusable higher-order helper
  • Edge cases for invalid and empty input

Definition of done

Demonstrate the happy path and at least two edge cases, keep responsibilities separated, and add a short note explaining one design choice.

Recap & quick check

Key takeaways

  • Functions are first-class values
  • Callbacks separate policy from mechanism
  • Recursion needs a base case
  • Composition works best with pure stages

Quick check

1. What is a higher-order function?

2. What prevents endless recursion?

3. What functions compose most predictably?

Keep the workshop. Later modules deliberately build on these decisions, so each exercise can become part of your final portfolio architecture.