Skip to the code
cf.

Counter with private state

Write makeCounter(start), where start defaults to 0. It returns an object with four methods: increment() and decrement() change the count by one and return the new count, reset() sets it back to start and returns it, and value() returns the current count.

The count is private: none of the object's properties holds it, so code outside can only change it through the methods. Every counter is independent, and the methods keep working when they're called on their own, without the object in front.

const counter = makeCounter(5);
counter.increment(); // 6
counter.increment(); // 7
counter.decrement(); // 6
counter.reset();     // 5
counter.count;       // undefined
 
const { increment, value } = counter;
increment();         // 6
value();             // 6

What the tests check

  1. starts at 0 by default
    expect(makeCounter().value()).toBe(0);
    
  2. increment and decrement return the new count
    const counter = makeCounter(5);
    expect(counter.increment()).toBe(6);
    expect(counter.increment()).toBe(7);
    expect(counter.decrement()).toBe(6);
    expect(counter.value()).toBe(6);
    
  3. reset goes back to start and returns it
    const counter = makeCounter(5);
    counter.increment();
    counter.increment();
    expect(counter.reset()).toBe(5);
    expect(counter.value()).toBe(5);
    
  4. counters are independent
    const a = makeCounter();
    const b = makeCounter(10);
    a.increment();
    a.increment();
    b.decrement();
    expect(a.value()).toBe(2);
    expect(b.value()).toBe(9);
    expect(a.reset()).toBe(0);
    expect(b.reset()).toBe(10);
    
  5. no property holds the count
    const counter = makeCounter(3);
    counter.increment();
    const notMethods = Reflect.ownKeys(counter).filter((key) => typeof counter[key] !== "function");
    expect(notMethods).toEqual([]);
    
  6. the methods work on their own, without the object
    const { increment, decrement, reset, value } = makeCounter(1);
    increment();
    increment();
    decrement();
    expect(value()).toBe(2);
    expect(reset()).toBe(1);
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).