JavaScript classes and private fields

Protect instance state with a private class field.

JavaScript
class Counter {
  #value = 0;
  increment() { this.#value += 1; }
  get value() { return this.#value; }
}
const first = new Counter();
const second = new Counter();
first.increment();
first.increment();
console.log(first.value, second.value);
if (second.value !== 0) throw new Error("shared state");
Output
2 0

Explanation

class provides syntax for constructing objects with shared methods. A # field is private class state and can only be accessed from the declaring class's body.

A getter exposes a read-only public view without requiring callers to invoke a method. Each instance receives its own private field.

Explore the dry run
Guided walkthroughReady
1class Counter {
2 #value = 0;
3 increment() { this.#value += 1; }
4 get value() { return this.#value; }
5}
6const first = new Counter();
7const second = new Counter();
8first.increment();
9first.increment();
10console.log(first.value, second.value);
11if (second.value !== 0) throw new Error("shared state");

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Create the first private value.first.#value = 0
—
Create a separate second value.second.#value = 0
—
The two method calls update first from 0 to 1 to 2.first.#value = 2, second.#value = 0
—
The getter returns each instance's value.first.#value = 2, second.#value = 0
—
Print the public views.first.#value = 2, second.#value = 0
2 0

Cost and common mistakes

O(1) work per increment and O(1) state per object.

  • Accessing first.#value outside the class is a syntax error.
  • Calling an extracted method without the correct receiver can lose this binding.

Try it yourself

Add a reset method and call it on first.

Reveal answer and reasoning

Inside the class, reset() can assign this.#value = 0. The output then becomes 0 0.

Further reading