ES6 Classes in JavaScript Explained

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.