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
| Aspect | Description |
|---|---|
| Introduced | ES6 (ECMAScript 2015) |
| Purpose | Concise syntax for creating objects and inheritance |
| Under the hood | Syntactic sugar over prototype-based inheritance |
| Not hoisted | Classes must be defined before use |
| Strict mode | Class 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:
| Line | Description |
|---|---|
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
functionkeyword needed - No commas between methods
- Methods are stored on the prototype (shared by all instances)
thisrefers to the instance the method is called on
Part 3: Creating an Instance
const alice = new Person('Alice', 30);
What happens with new:
| Step | Description |
|---|---|
| 1 | A new empty object is created |
| 2 | The constructor is called with 'Alice' and 30 |
| 3 | this inside the constructor refers to the new object |
| 4 | The 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:
- Look for
greetonalice— not found - Look up the prototype chain → found on
Person.prototype - 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:
| Aspect | Class Notation | Function Notation |
|---|---|---|
| Syntax | Cleaner, more readable | More verbose |
| Hoisting | Not hoisted | Function declarations are hoisted |
| Strict mode | Always strict | Only if declared |
new required | Yes — throws error otherwise | No — can be called without new |
| Methods | Shared prototype | Manual prototype assignment |
| Inheritance | extends keyword | Manual prototype chain |
Class Features Overview
| Feature | Syntax | Purpose |
|---|---|---|
| Constructor | constructor() { } | Initialize the instance |
| Method | name() { } | Define behavior |
| Getter | get name() { } | Computed property read |
| Setter | set name(v) { } | Computed property write |
| Static method | static name() { } | Belongs to class, not instances |
| Static field | static name = value; | Shared across all instances |
| Class field | name = value; | Per-instance property |
| Private field | #name = value; | Only accessible inside class |
| Inheritance | class B extends A { } | Inherit from parent class |
| Super call | super(args) | Call parent constructor |
| Super method | super.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
| Feature | Syntax |
|---|---|
| Declaration | class Name { } |
| Constructor | constructor(params) { } |
| Method | name() { } |
| Class field | prop = value; |
| Private field | #name; |
| Getter | get name() { } |
| Setter | set name(v) { } |
| Static method | static name() { } |
| Static field | static name = value; |
| Inheritance | class B extends A { } |
| Super call | super(args) |
Class vs Function Notation
| Aspect | Class | Function |
|---|---|---|
| Syntax | Cleaner | Verbose |
| Strict mode | Always | Optional |
| Hoisting | Not hoisted | Hoisted |
new required | ✅ Yes | ❌ No |
| Methods | Class body | Manual prototype |
| Inheritance | extends | Manual chain |
What Happens with new
| Step | Action |
|---|---|
| 1 | New empty object created |
| 2 | Constructor called with args |
| 3 | this set to new object |
| 4 | Properties added via this |
| 5 | Object 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
| Pitfall | Problem | Solution |
|---|---|---|
Forgetting new | TypeError | Always use new |
Missing super() | ReferenceError | Call super() first |
| Hoisting assumption | ReferenceError | Define before use |
| Method binding | this lost | Use arrow functions or bind |
| Private field outside class | SyntaxError | Only use # inside class |
| Overusing inheritance | Rigid design | Prefer composition |
When to Use Classes
| Scenario | Recommended? |
|---|---|
| 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
newto instantiate — classes throw without it - Use
super()in subclasses before accessingthis - 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!