ES6 classes gave JavaScript a syntax familiar to developers from class-based languages — but underneath, it’s still the same prototype-based inheritance the language always had, just with cleaner syntax on top.
class Shape {
#color; // private field (# prefix), genuinely inaccessible from outside
constructor(color) {
this.#color = color;
}
getColor() {
return this.#color;
}
static compare(a, b) {
return a.getColor() === b.getColor();
}
}
class Circle extends Shape {
constructor(color, radius) {
super(color); // must call before using <code>this</code>
this.radius = radius;
}
get area() { // getter - accessed like a property, not called like a method
return Math.PI * this.radius ** 2;
}
}
const c = new Circle('red', 5);
console.log(c.area); // 78.54..., no parentheses needed
Private fields (#field) are a genuine language feature, not just a naming convention like the old _field underscore prefix — code outside the class truly cannot access #color, even via bracket notation or reflection tricks that could bypass the old convention.