Since ES2022 a # prefix makes a field, method or accessor private, on instances or on the class (static #x). Using obj.#count outside the class body is a SyntaxError; subclasses cannot see it either, and #count in obj tests for the field safely. A static { } block runs once while the class is defined and may use try...catch and private statics. Symbols vs Private Fields compares private fields with Symbol keys.
class Counter {
#count = 0; // private field
static { console.log('static block runs once'); } // at class-definition time
#step() { return 1; } // private method
increment() { this.#count += this.#step(); return this; }
get value() { return this.#count; }
static isCounter(obj) { return #count in obj; } // ergonomic brand check
}
const c = new Counter().increment().increment();
console.log(c.value, Counter.isCounter(c), Counter.isCounter({}), JSON.stringify(c));
try { c.increment.call({}); } catch (e) { console.log(e.message); }static block runs once
2 true false {}
Cannot read private member #count from an object whose class did not declare it