|

JavaScript 31 🧬 Class notation

In JavaScript, classes were introduced in ES6 (ECMAScript 2015) to provide a more familiar and concise syntax for creating objects and handling inheritance compared to the traditional prototype-based approach. Classes in JavaScript are syntactic sugar over JavaScript’s existing prototype-based inheritance.


A Quick Look at the Example

// Define a class named Person
class Person {
    // Constructor method to initialize the object with name and age properties
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    // Method to display information about the person
    greet() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

// Creating an instance of the Person class
const alice = new Person('Alice', 30);

// Calling the method on the created instance
alice.greet(); // "Hello, my name is Alice and I am 30 years old."

What is Class Notation?

Class notation is the modern syntax for defining objects and their behavior in JavaScript. It provides a cleaner, more intuitive way to work with object-oriented programming (OOP) compared to the older prototype-based approach.

Key Points

AspectDescription
IntroducedES6 (ECMAScript 2015)
PurposeConcise syntax for creating objects and inheritance
Under the hoodSyntactic sugar over prototype-based inheritance
Not hoistedClasses must be defined before use
Strict modeClass bodies are always in strict mode

Anatomy of a Class

class Person {
    // 1. Constructor method
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    // 2. Methods
    greet() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }

    // 3. Getters
    get info() {
        return `${this.name}, ${this.age}`;
    }

    // 4. Setters
    set newAge(value) {
        if (value > 0) this.age = value;
    }

    // 5. Static methods
    static create(name, age) {
        return new Person(name, age);
    }

    // 6. Static fields
    static species = 'Homo sapiens';

    // 7. Class fields
    id = Math.random();

    // 8. Private fields
    #secret = 'hidden';
}

Part 1: Class Declaration

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}

Line by line:

LineDescription
class Person {Declares a class named Person
constructor(name, age) {Special method that runs when new Person() is called
this.name = name;Assigns the name argument to the instance’s name property
this.age = age;Assigns the age argument to the instance’s age property
}End of constructor
}End of class

Part 2: Methods

greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}

Key points:

  • Methods are defined inside the class body but outside the constructor
  • No function keyword needed
  • No commas between methods
  • Methods are stored on the prototype (shared by all instances)
  • this refers to the instance the method is called on

Part 3: Creating an Instance

const alice = new Person('Alice', 30);

What happens with new:

StepDescription
1A new empty object is created
2The constructor is called with 'Alice' and 30
3this inside the constructor refers to the new object
4The new object is returned and assigned to alice

Visual:

new Person('Alice', 30)
       │
       ▼
┌─────────────────────┐
│  1. Create {}       │
│  2. Run constructor │
│  3. this = {}       │
│  4. this.name = 'Alice'
│  5. this.age = 30   │
│  6. Return {}       │
└─────────────────────┘
       │
       ▼
   alice = { name: 'Alice', age: 30 }

Part 4: Calling Methods

alice.greet(); // "Hello, my name is Alice and I am 30 years old."

Lookup process:

  1. Look for greet on alicenot found
  2. Look up the prototype chain → found on Person.prototype
  3. Call it with this = alice

Class Notation vs Function Notation

// ✅ Class notation (modern)
class Person {
    constructor(name) {
        this.name = name;
    }
    greet() {
        return `Hi, ${this.name}`;
    }
}

// 🔄 Function notation (classic) — equivalent
function PersonOld(name) {
    this.name = name;
}
PersonOld.prototype.greet = function() {
    return `Hi, ${this.name}`;
};

Comparison:

AspectClass NotationFunction Notation
SyntaxCleaner, more readableMore verbose
HoistingNot hoistedFunction declarations are hoisted
Strict modeAlways strictOnly if declared
new requiredYes — throws error otherwiseNo — can be called without new
MethodsShared prototypeManual prototype assignment
Inheritanceextends keywordManual prototype chain

Class Features Overview

FeatureSyntaxPurpose
Constructorconstructor() { }Initialize the instance
Methodname() { }Define behavior
Getterget name() { }Computed property read
Setterset name(v) { }Computed property write
Static methodstatic name() { }Belongs to class, not instances
Static fieldstatic name = value;Shared across all instances
Class fieldname = value;Per-instance property
Private field#name = value;Only accessible inside class
Inheritanceclass B extends A { }Inherit from parent class
Super callsuper(args)Call parent constructor
Super methodsuper.method()Call parent method

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Class Notation</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            line-height: 1.6;
        }
        h1 { color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; }
        h2 { color: #28a745; border-left: 4px solid #28a745; padding-left: 15px; margin-top: 30px; }
        .demo-box {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 15px 0;
        }
        pre {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
        }
        .keyword { color: #569cd6; }
        .string { color: #ce9178; }
        .number { color: #b5cea8; }
        .function { color: #dcdcaa; }
        .comment { color: #6a9955; }
        .boolean { color: #569cd6; }
        .class-name { color: #4ec9b0; }
        .private { color: #c586c0; }
        #output {
            background: #e9ecef;
            padding: 15px;
            border-radius: 8px;
            margin-top: 15px;
            min-height: 40px;
            font-family: 'Courier New', monospace;
            font-size: 0.85rem;
            border-left: 4px solid #007bff;
            white-space: pre-wrap;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }
        th, td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }
        th { background: #007bff; color: white; }
        tr:nth-child(even) { background: #f8f9fa; }
        .btn {
            padding: 10px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            margin: 5px;
            transition: all 0.3s;
        }
        .btn:hover {
            background: #0056b3;
            transform: translateY(-2px);
        }
        .btn-success { background: #28a745; }
        .btn-success:hover { background: #1e7e34; }
        .class-display {
            font-family: 'Courier New', monospace;
            font-size: 1.05em;
            background: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            white-space: pre-wrap;
            line-height: 1.8;
        }
        .comparison-grid {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
            margin: 15px 0;
        }
        .comparison-grid > div {
            flex: 1;
            min-width: 280px;
            padding: 15px;
            border-radius: 8px;
        }
        .class-box {
            background: #d4edda;
            border-left: 4px solid #28a745;
        }
        .function-box {
            background: #fff3cd;
            border-left: 4px solid #ffc107;
        }
        .input-group {
            margin: 10px 0;
        }
        .input-group label {
            display: inline-block;
            min-width: 150px;
            font-weight: bold;
        }
        .input-group input {
            padding: 8px 12px;
            border: 2px solid #ddd;
            border-radius: 6px;
            font-size: 1em;
            width: 200px;
        }
        .input-group input:focus {
            outline: none;
            border-color: #007bff;
        }
    </style>
</head>
<body>

    <h1>Class Notation</h1>

    <div class="demo-box">
        <h2>1. Basic Class Notation</h2>
        <pre>
<span class="keyword">class</span> <span class="class-name">Person</span> {
    <span class="function">constructor</span>(name, age) {
        <span class="keyword">this</span>.name = name;
        <span class="keyword">this</span>.age = age;
    }

    <span class="function">greet</span>() {
        console.log(<span class="string">`Hello, my name is ${this.name} and I am ${this.age} years old.`</span>);
    }
}

<span class="keyword">const</span> alice = <span class="keyword">new</span> <span class="class-name">Person</span>(<span class="string">'Alice'</span>, <span class="number">30</span>);
alice.<span class="function">greet</span>();
        </pre>
    </div>

    <div class="demo-box">
        <h2>2. Anatomy of a Class</h2>
        <pre>
<span class="keyword">class</span> <span class="class-name">MyClass</span> {
    <span class="comment">// 1. Class field (per-instance)</span>
    id = Math.<span class="function">random</span>();

    <span class="comment">// 2. Private field</span>
    <span class="private">#secret</span> = <span class="string">'hidden'</span>;

    <span class="comment">// 3. Constructor</span>
    <span class="function">constructor</span>(param) {
        <span class="keyword">this</span>.param = param;
    }

    <span class="comment">// 4. Method</span>
    <span class="function">method</span>() { }

    <span class="comment">// 5. Getter</span>
    <span class="keyword">get</span> <span class="function">value</span>() { <span class="keyword">return</span> <span class="keyword">this</span>.param; }

    <span class="comment">// 6. Setter</span>
    <span class="keyword">set</span> <span class="function">value</span>(v) { <span class="keyword">this</span>.param = v; }

    <span class="comment">// 7. Static method</span>
    <span class="keyword">static</span> <span class="function">create</span>() { <span class="keyword">return</span> <span class="keyword">new</span> <span class="class-name">MyClass</span>(); }

    <span class="comment">// 8. Static field</span>
    <span class="keyword">static</span> version = <span class="string">'1.0'</span>;
}
        </pre>
    </div>

    <div class="demo-box">
        <h2>3. Class vs Function Notation</h2>
        <div class="comparison-grid">
            <div class="class-box">
                <h3>✅ Class Notation (Modern)</h3>
                <pre style="background: #fff; color: #333; font-size: 0.8rem;">
<span class="keyword">class</span> <span class="class-name">Person</span> {
    <span class="function">constructor</span>(name) {
        <span class="keyword">this</span>.name = name;
    }
    <span class="function">greet</span>() {
        <span class="keyword">return</span> <span class="string">`Hi, ${this.name}`</span>;
    }
}
                </pre>
                <ul>
                    <li>Cleaner syntax</li>
                    <li>Always strict mode</li>
                    <li>Requires <code>new</code></li>
                    <li>Not hoisted</li>
                </ul>
            </div>
            <div class="function-box">
                <h3>🔄 Function Notation (Classic)</h3>
                <pre style="background: #fff; color: #333; font-size: 0.8rem;">
<span class="keyword">function</span> <span class="function">PersonOld</span>(name) {
    <span class="keyword">this</span>.name = name;
}
<span class="function">PersonOld</span>.prototype.greet = <span class="keyword">function</span>() {
    <span class="keyword">return</span> <span class="string">`Hi, ${this.name}`</span>;
};
                </pre>
                <ul>
                    <li>More verbose</li>
                    <li>Can be called without <code>new</code></li>
                    <li>Function declarations hoisted</li>
                    <li>Manual prototype setup</li>
                </ul>
            </div>
        </div>
    </div>

    <div class="demo-box">
        <h2>4. Class Features Reference</h2>
        <table>
            <tr>
                <th>Feature</th>
                <th>Syntax</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><strong>Declaration</strong></td>
                <td><code>class Name { }</code></td>
                <td><code>class Person { }</code></td>
            </tr>
            <tr>
                <td><strong>Constructor</strong></td>
                <td><code>constructor() { }</code></td>
                <td><code>constructor(name) { this.name = name; }</code></td>
            </tr>
            <tr>
                <td><strong>Method</strong></td>
                <td><code>name() { }</code></td>
                <td><code>greet() { return "Hi"; }</code></td>
            </tr>
            <tr>
                <td><strong>Class field</strong></td>
                <td><code>prop = value;</code></td>
                <td><code>id = 1;</code></td>
            </tr>
            <tr>
                <td><strong>Private field</strong></td>
                <td><code>#name;</code></td>
                <td><code>#balance = 0;</code></td>
            </tr>
            <tr>
                <td><strong>Getter</strong></td>
                <td><code>get name() { }</code></td>
                <td><code>get fullName() { }</code></td>
            </tr>
            <tr>
                <td><strong>Setter</strong></td>
                <td><code>set name(v) { }</code></td>
                <td><code>set age(v) { }</code></td>
            </tr>
            <tr>
                <td><strong>Static method</strong></td>
                <td><code>static name() { }</code></td>
                <td><code>static create() { }</code></td>
            </tr>
            <tr>
                <td><strong>Static field</strong></td>
                <td><code>static name = value;</code></td>
                <td><code>static version = '1.0';</code></td>
            </tr>
            <tr>
                <td><strong>Inheritance</strong></td>
                <td><code>class B extends A { }</code></td>
                <td><code>class Dog extends Animal { }</code></td>
            </tr>
            <tr>
                <td><strong>Super</strong></td>
                <td><code>super(args)</code></td>
                <td><code>super(name)</code></td>
            </tr>
        </table>
    </div>

    <div class="demo-box">
        <h2>5. Interactive: Person Class Demo</h2>
        <div class="input-group">
            <label for="pName">Name:</label>
            <input type="text" id="pName" value="Alice">
        </div>
        <div class="input-group">
            <label for="pAge">Age:</label>
            <input type="number" id="pAge" value="30">
        </div>
        <div style="margin: 10px 0;">
            <button class="btn btn-success" onclick="createAndGreet()">Create & Greet</button>
            <button class="btn" onclick="showProperties()">Show Properties</button>
            <button class="btn" onclick="checkInstance()">Check Instance</button>
            <button class="btn" onclick="compareNotation()">Compare with Function</button>
        </div>
        <div class="class-display" id="classDisplay">Click a button to see the class in action</div>
    </div>

    <div class="demo-box">
        <h2>6. Live Output — All Examples</h2>
        <div id="output">Loading...</div>
    </div>

    <script>
        // ============================================
        // Class Notation — Live Demo
        // ============================================

        let results = [];

        // 1. Basic class
        results.push('📌 Basic Class Definition:\n');

        class Person {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }

            greet() {
                return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
            }
        }

        const alice = new Person('Alice', 30);
        results.push('  const alice = new Person("Alice", 30)');
        results.push('  alice.greet() → "' + alice.greet() + '"');
        results.push('');

        // 2. Class is a function
        results.push('📌 Class is a Function (Syntactic Sugar):\n');
        results.push('  typeof Person → ' + typeof Person);
        results.push('  Person.prototype.greet → ' + typeof Person.prototype.greet);
        results.push('  → Classes are functions with a prototype!');
        results.push('');

        // 3. Instance checks
        results.push('📌 Instance Checks:\n');
        results.push('  alice instanceof Person → ' + (alice instanceof Person));
        results.push('  alice instanceof Object → ' + (alice instanceof Object));
        results.push('  Object.getPrototypeOf(alice) === Person.prototype → ' +
            (Object.getPrototypeOf(alice) === Person.prototype));
        results.push('');

        // 4. Class fields
        results.push('📌 Class Fields:\n');

        class Counter {
            count = 0; // Class field with default
            #secret = 'hidden'; // Private field

            increment() {
                this.count++;
                return this.count;
            }

            getSecret() {
                return this.#secret;
            }
        }

        const c1 = new Counter();
        const c2 = new Counter();
        c1.increment();
        c1.increment();
        c1.increment();
        c2.increment();

        results.push('  c1.increment() × 3 → ' + c1.count);
        results.push('  c2.increment() × 1 → ' + c2.count);
        results.push('  → Each instance has its OWN count');
        results.push('  c1.getSecret() → "' + c1.getSecret() + '" (via method)');
        results.push('  c1.#secret → ❌ Private, cannot access!');
        results.push('');

        // 5. Static members
        results.push('📌 Static Members:\n');

        class MathUtil {
            static PI = 3.14159;
            static add(a, b) { return a + b; }
            static multiply(a, b) { return a * b; }
        }

        results.push('  MathUtil.PI → ' + MathUtil.PI);
        results.push('  MathUtil.add(5, 3) → ' + MathUtil.add(5, 3));
        results.push('  MathUtil.multiply(4, 7) → ' + MathUtil.multiply(4, 7));
        results.push('  → Static members belong to the CLASS');
        results.push('');

        // 6. Getters and setters
        results.push('📌 Getters and Setters:\n');

        class Circle {
            #radius;

            constructor(radius) {
                this.#radius = radius;
            }

            get radius() {
                return this.#radius;
            }

            set radius(value) {
                if (value < 0) throw new Error("Radius must be positive");
                this.#radius = value;
            }

            get area() {
                return Math.PI * this.#radius ** 2;
            }

            get circumference() {
                return 2 * Math.PI * this.#radius;
            }
        }

        const circle = new Circle(5);
        results.push('  const circle = new Circle(5)');
        results.push('  circle.radius → ' + circle.radius);
        results.push('  circle.area → ' + circle.area.toFixed(2));
        results.push('  circle.circumference → ' + circle.circumference.toFixed(2));
        circle.radius = 10;
        results.push('  After circle.radius = 10:');
        results.push('  circle.area → ' + circle.area.toFixed(2));
        results.push('');

        // 7. Inheritance
        results.push('📌 Inheritance:\n');

        class Animal {
            constructor(name) {
                this.name = name;
            }

            speak() {
                return `${this.name} makes a sound.`;
            }
        }

        class Dog extends Animal {
            constructor(name, breed) {
                super(name);
                this.breed = breed;
            }

            bark() {
                return `${this.name} barks!`;
            }

            speak() {
                return `${this.name} barks.`;
            }
        }

        const dog = new Dog('Rex', 'Labrador');
        results.push('  const dog = new Dog("Rex", "Labrador")');
        results.push('  dog.name → "' + dog.name + '" (inherited)');
        results.push('  dog.breed → "' + dog.breed + '" (own)');
        results.push('  dog.speak() → "' + dog.speak() + '" (overridden)');
        results.push('  dog.bark() → "' + dog.bark() + '" (own)');
        results.push('');

        // 8. Class vs Function comparison
        results.push('📌 Class vs Function Notation:\n');

        function PersonOld(name) {
            this.name = name;
        }
        PersonOld.prototype.greet = function() {
            return `Hi, ${this.name}`;
        };

        const oldPerson = new PersonOld('Bob');
        const newPerson = new Person('Carol', 25);

        results.push('  Function: new PersonOld("Bob").greet() → "' + oldPerson.greet() + '"');
        results.push('  Class:    new Person("Carol", 25).greet() → "' + newPerson.greet() + '"');
        results.push('  → Same behavior, cleaner syntax!');
        results.push('');

        // 9. Calling class without new
        results.push('📌 Calling Class Without new:\n');
        try {
            // Uncomment to see the error:
            // const bad = Person('Test', 1);
            results.push('  Person("Test", 1) → ❌ TypeError: Class constructor cannot be invoked without new');
            results.push('  → Classes REQUIRE the new keyword!');
        } catch (error) {
            results.push('  Error: ' + error.message);
        }
        results.push('');

        // 10. Practical: Todo class
        results.push('📌 Practical: Todo Class:\n');

        class Todo {
            static nextId = 1;

            constructor(title) {
                this.id = Todo.nextId++;
                this.title = title;
                this.completed = false;
                this.createdAt = new Date();
            }

            complete() {
                this.completed = true;
                return this;
            }

            toString() {
                const status = this.completed ? '✅' : '⬜';
                return `${status} [${this.id}] ${this.title}`;
            }
        }

        const todo1 = new Todo('Learn JavaScript');
        const todo2 = new Todo('Build a project');

        results.push('  ' + todo1.toString());
        results.push('  ' + todo2.toString());
        todo1.complete();
        results.push('  After todo1.complete():');
        results.push('  ' + todo1.toString());
        results.push('');

        // 11. Practical: User class
        results.push('📌 Practical: User Class with Validation:\n');

        class User {
            #email;

            constructor(name, email) {
                this.name = name;
                this.email = email; // Uses setter
            }

            get email() {
                return this.#email;
            }

            set email(value) {
                if (!value.includes('@')) {
                    throw new Error('Invalid email format');
                }
                this.#email = value.toLowerCase();
            }

            toString() {
                return `${this.name} <${this.#email}>`;
            }
        }

        const user = new User('Alice', 'Alice@Example.COM');
        results.push('  const user = new User("Alice", "Alice@Example.COM")');
        results.push('  user.toString() → "' + user.toString() + '"');
        results.push('  → Email was lowercased by the setter');

        try {
            new User('Bob', 'invalid-email');
        } catch (error) {
            results.push('  new User("Bob", "invalid-email") → ❌ ' + error.message);
        }

        document.getElementById('output').textContent = results.join('\n');

        // ============================================
        // Interactive: Person Class Demo
        // ============================================

        function createAndGreet() {
            const name = document.getElementById('pName').value;
            const age = Number(document.getElementById('pAge').value);
            const person = new Person(name, age);
            const display = document.getElementById('classDisplay');

            display.textContent =
                `👤 Creating Person\n` +
                `─────────────────────\n` +
                `const person = new Person("${name}", ${age});\n` +
                `person.greet()\n` +
                `\n` +
                `Output:\n"${person.greet()}"`;
        }

        function showProperties() {
            const name = document.getElementById('pName').value;
            const age = Number(document.getElementById('pAge').value);
            const person = new Person(name, age);
            const display = document.getElementById('classDisplay');

            display.textContent =
                `📋 Person Properties\n` +
                `─────────────────────\n` +
                `name: "${person.name}"\n` +
                `age: ${person.age}\n` +
                `\n` +
                `Own properties: ${Object.keys(person).join(', ')}\n` +
                `Prototype methods: ${Object.getOwnPropertyNames(Person.prototype).filter(k => k !== 'constructor').join(', ')}`;
        }

        function checkInstance() {
            const name = document.getElementById('pName').value;
            const age = Number(document.getElementById('pAge').value);
            const person = new Person(name, age);
            const display = document.getElementById('classDisplay');

            display.textContent =
                `🔍 Instance Checks\n` +
                `─────────────────────\n` +
                `person instanceof Person → ${person instanceof Person}\n` +
                `person instanceof Object → ${person instanceof Object}\n` +
                `typeof Person → ${typeof Person}\n` +
                `Object.getPrototypeOf(person) === Person.prototype → ${Object.getPrototypeOf(person) === Person.prototype}\n` +
                `person.constructor === Person → ${person.constructor === Person}`;
        }

        function compareNotation() {
            const display = document.getElementById('classDisplay');

            display.textContent =
                `🔄 Class vs Function Notation\n` +
                `─────────────────────────────\n` +
                `\n` +
                `CLASS (modern):\n` +
                `  class Person {\n` +
                `    constructor(name) { this.name = name; }\n` +
                `    greet() { return \`Hi, \${this.name}\`; }\n` +
                `  }\n` +
                `\n` +
                `FUNCTION (classic):\n` +
                `  function PersonOld(name) {\n` +
                `    this.name = name;\n` +
                `  }\n` +
                `  PersonOld.prototype.greet = function() {\n` +
                `    return \`Hi, \${this.name}\`;\n` +
                `  };\n` +
                `\n` +
                `→ Both produce the same result!\n` +
                `→ Classes are SYNTACTIC SUGAR over prototypes.`;
        }
    </script>

</body>
</html>

Quick Reference

Class Syntax

FeatureSyntax
Declarationclass Name { }
Constructorconstructor(params) { }
Methodname() { }
Class fieldprop = value;
Private field#name;
Getterget name() { }
Setterset name(v) { }
Static methodstatic name() { }
Static fieldstatic name = value;
Inheritanceclass B extends A { }
Super callsuper(args)

Class vs Function Notation

AspectClassFunction
SyntaxCleanerVerbose
Strict modeAlwaysOptional
HoistingNot hoistedHoisted
new required✅ Yes❌ No
MethodsClass bodyManual prototype
InheritanceextendsManual chain

What Happens with new

StepAction
1New empty object created
2Constructor called with args
3this set to new object
4Properties added via this
5Object returned

Best Practices

Do This:

// Use PascalCase for class names
class Person { }

// Always use `new` to instantiate
const person = new Person("Alice", 30);

// Call super() in subclass constructors
class Dog extends Animal {
    constructor(name) {
        super(name);
    }
}

// Use private fields for internal state
class BankAccount {
    #balance = 0;
}

// Use static methods for utilities
class MathUtil {
    static add(a, b) { return a + b; }
}

// Use getters for computed properties
class Circle {
    get area() { return Math.PI * this.#radius ** 2; }
}

Don’t Do This:

// Don't call class without `new`
const p = Person("Alice"); // ❌ TypeError

// Don't forget super() in subclass
class Dog extends Animal {
    constructor(name) {
        this.name = name; // ❌ ReferenceError
        super(name);
    }
}

// Don't use lowercase for class names
class person { } // ⚠️ Convention violation

// Don't overuse classes for simple data
class Point {
    constructor(x, y) { this.x = x; this.y = y; }
}
// Simpler: const point = { x: 1, y: 2 };

// Don't add methods outside the class body in class syntax
class Person { }
Person.prototype.greet = function() { }; // ⚠️ Works, but not idiomatic

Common Pitfalls

PitfallProblemSolution
Forgetting newTypeErrorAlways use new
Missing super()ReferenceErrorCall super() first
Hoisting assumptionReferenceErrorDefine before use
Method bindingthis lostUse arrow functions or bind
Private field outside classSyntaxErrorOnly use # inside class
Overusing inheritanceRigid designPrefer composition

When to Use Classes

ScenarioRecommended?
Data models (User, Product)✅ Yes
Multiple similar objects✅ Yes
Inheritance needed✅ Yes
Custom errors✅ Yes
Singleton state❌ Use plain object
Simple data containers❌ Use plain objects
Stateless utilities❌ Use functions

Pro Tip: Classes provide a clean, familiar syntax for object-oriented programming in JavaScript. They’re the modern way to create objects with shared behavior and inheritance.

Key reminders:

  • Classes are syntactic sugar over prototypes — same underlying mechanism
  • Use new to instantiate — classes throw without it
  • Use super() in subclasses before accessing this
  • Use private fields (#) for true encapsulation
  • Use static for class-level utilities
  • Classes are not hoisted — define before use

But remember: Don’t overuse classes! For simple data, plain objects work great. For utility functions, plain functions work great. Use classes when you need encapsulation, inheritance, or multiple instances of similar objects with shared behavior.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!