JavaScript classes are the modern blueprint syntax for creating objects that bundle data and behavior together. This lesson covers constructors, methods, inheritance with extends and super, static methods, getters/setters, and true private state with # fields.
1JS Classes & Inheritance - In-Depth Guide Part 1
Welcome! Classes are the modern blueprints for creating objects in JavaScript. They wrap data and logic into one package.
// The Modern BlueprintClasses
2JS Classes & Inheritance - In-Depth Guide Part 2
A class starts with a constructor. This special method runs automatically whenever you create a new instance.
class Hero {
constructor(name, power) {
this.name = name;
this.power = power;
}
}Constructor
➡️
constructor() runs
3JS Classes & Inheritance - In-Depth Guide Part 3
You can add methods to define what the object can DO. Unlike functions, you don't need the 'function' keyword inside a class.
class Hero {
// ... constructor
usePower() {
return `${this.name} uses ${this.power}!`;
}
}Methods
4JS Classes & Inheritance - In-Depth Guide Part 4
Inheritance allows a class to take everything from another class. We use 'extends' to build on top of a parent class.
class FlyingHero extends Hero {
constructor(name, power, altitude) {
super(name, power); // Call parent constructor
this.altitude = altitude;
}
}Inheritance
⬇️ extends
FlyingHero
5JS Classes & Inheritance - In-Depth Guide Part 5
The 'super' keyword is critical. It calls the parent's methods or constructor so you don't have to rewrite code.
usePower() {
const basic = super.usePower();
return `${basic} from the sky!`;
}super()
6JS Classes & Inheritance - In-Depth Guide Part 6
Static methods belong to the class itself, not to the instances. They are often used for utility functions.
class Hero {
static isHero(obj) {
return obj instanceof Hero;
}
}Static Methods
7JS Classes & Inheritance - In-Depth Guide Part 7
Getters and Setters allow you to control how properties are accessed and modified, adding a layer of logic.
get info() {
return `${this.name} (${this.power})`;
}
set info(val) {
this.name = val.toUpperCase();
}Get / Set
8JS Classes & Inheritance - In-Depth Guide Part 8
Finally, private fields (using #) ensure that internal data cannot be accessed from outside the class.
class Wallet {
#balance = 0; // Private
deposit(amount) {
this.#balance += amount;
}
}Private Fields
9JS Classes & Inheritance - In-Depth Guide Part 9
Classes, inheritance, and encapsulation mastered! You can now build complex, reusable systems.
<h1>OOP: Mastered</h1>OOP Mastered
10Step-by-Step Breakdown
Welcome! Classes are the modern blueprints for creating objects in JavaScript. They wrap data and logic into one package.
A class starts with a constructor. This special method runs automatically whenever you create a new instance.
You can add methods to define what the object can DO. Unlike functions, you don't need the 'function' keyword inside a class.
Checkpoint: Which keyword is used to create a new instance (an actual object) from a class?
- →create
- →new
- →instanceof
Inheritance allows a class to take everything from another class. We use 'extends' to build on top of a parent class.
The 'super' keyword is critical. It calls the parent's methods or constructor so you don't have to rewrite code.
Checkpoint: In a subclass constructor, what MUST you call before using 'this'?
- →parent()
- →super()
- →this.init()
Static methods belong to the class itself, not to the instances. They are often used for utility functions.
Getters and Setters allow you to control how properties are accessed and modified, adding a layer of logic.
Finally, private fields (using #) ensure that internal data cannot be accessed from outside the class.
Final Challenge: Which prefix marks a field as private in modern JavaScript classes?
- →underscore (_)
- →hash (#)
- →exclamation (!)
Classes, inheritance, and encapsulation mastered! You can now build complex, reusable systems.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Use Getters to Compute ARIA Attribute Strings from a Class's Internal State
A UI widget modeled as a class (e.g. a custom Accordion or Tabs component) can expose a getter like `get ariaExpanded()` that derives the correct `'true'`/`'false'` string from its private state — keeping the accessible attribute always in sync with the object's actual open/closed status instead of manually duplicating that logic at every call site.
SEO Implications
- 1
Classes Themselves Have No Direct SEO Effect, But Broken Inheritance Chains Can Crash Rendering
A subclass that forgets to call super() before using 'this' throws a ReferenceError at construction time, which can crash the component tree responsible for rendering visible page content — search engine crawlers that execute JavaScript will then see a broken or blank page instead of the intended content.
Best Practices
Always Call super() First in a Subclass Constructor Before Using 'this'
A derived class's constructor must call super() to run the parent class's constructor and properly initialize the inherited 'this' context before it can read or set any properties — attempting to use 'this' before that call throws a ReferenceError.
Use Private Fields (#) Instead of a Naming Convention for Truly Internal State
Prefixing a property with an underscore (like _balance) is only a convention — nothing stops external code from reading or mutating it directly. A genuine private field (#balance) is enforced by the JavaScript engine itself and is completely inaccessible from outside the class.
Frequent Bugs
A subclass's constructor throws 'Must call super constructor before accessing this' or similar.
In a class that extends another, `this` doesn't exist until super() has been called, because the parent constructor is responsible for setting it up. Always call super(...) as the very first statement in a subclass constructor, before referencing `this` in any way.
Code outside a class tries to access a private field directly (e.g. `instance.#balance`) and throws a SyntaxError.
Private fields (prefixed with #) are only accessible from inside the class body that declares them — even subclasses can't reach a parent's private fields directly. Expose a public method or getter (like `getBalance()`) if external code needs read access to that value.
Real-World Examples
Modeling a Bank Account with Private State
A BankAccount class needed to guarantee that its balance could never be set to an invalid value or modified directly from outside code, so the balance was stored as a private field and only exposed through controlled deposit and withdraw methods.
class BankAccount {
#balance = 0;
deposit(amount) {
if (amount <= 0) throw new Error('Deposit must be positive');
this.#balance += amount;
}
withdraw(amount) {
if (amount > this.#balance) throw new Error('Insufficient funds');
this.#balance -= amount;
}
get balance() {
return this.#balance;
}
}