Course outline
Full-Stack course / JavaScript fundamentals

Make a counter

Lab

How to fetch and submit this exercise

Once: install the tool and connect your account.

curl -fsSL https://gonomicon.com/install.sh | sh
gonomicon login

Each exercise: download it, edit the file named in the instructions, then submit.

gonomicon fetch fs-week-2/02-05-make-counter
cd 02-05-make-counter
gonomicon submit

The runner depends on the exercise: JavaScript/TypeScript/React labs run with Vitest, Python labs with pytest, and config-file labs (Docker, CI, Terraform, Nginx) are checked by parsing your file. gonomicon test runs the visible checks on your computer first; submitting also runs the hidden checks on our server.

Make a counter

Write two functions that build other functions: each one returns a small machine that remembers something about itself, call after call, without using any variable outside it.

Worked example

Here's a closure that remembers a running total instead of a count:

function makeAdder(start = 0) {
  let total = start;
  return function add(amount) {
    total += amount;
    return total;
  };
}

const tab = makeAdder(10);
console.log(tab(5));
console.log(tab(3));

const otherTab = makeAdder();
console.log(otherTab(100));
15
18
100

tab and otherTab each got their own private total from their own call to makeAdder - adding to one never touches the other.

Your task

Write function makeCounter(start = 0, step = 1). It returns a function that takes no arguments. The first time you call that returned function, it gives back start. Every call after that adds step to the running value and gives back the new value.

Write function makeLimiter(max). It returns a function that takes no arguments. The returned function gives back true for its first max calls, and false for every call after that.

Rules

  • Both makeCounter and makeLimiter must be top-level function declarations (not arrow functions stored in a const), since that's the shape the lesson's examples use.
  • Every counter or limiter must keep its own private state - nothing stored outside the function that built it, and nothing shared between two counters (or two limiters) made from separate calls.
  • makeCounter's returned function takes no arguments - start and step are only ever set once, when you call makeCounter itself.
  • Don't reach for anything beyond if/else, default parameters, and a closure's own private variables - no arrays, no loops needed here.

What you'll practice

Writing a function that returns a function, giving it private state through a closure, and using default parameters and a plain if to shape what each call gives back.

Run it

gonomicon fetch fs-week-2/02-05-make-counter
cd 02-05-make-counter
gonomicon test
gonomicon submit

Hints

  1. A closure is just a function returning another function - the inner function is what you hand back, and it can see the outer function's variables even after the outer call is over.
  2. The counter's very first call should return start itself, not start + step - only the calls after the first one add step.
  3. makeLimiter only needs to remember how many times it has been called so far, and compare that count to max on every call.