Lesson 12 • Expert
Prototypes and Classes
Master JavaScript's object model, prototypal inheritance, and modern ES6 classes.
What You'll Learn in This Lesson
- ✓Understand prototype-based inheritance
- ✓How the prototype chain works
- ✓Create objects with Object.create()
- ✓Use ES6 Classes (syntactic sugar)
- ✓Static methods and private fields
- ✓Inheritance with 'extends' and 'super'
💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:
- Download Node.js to run JavaScript on your computer
- Use your browser's Developer Console (Press F12) to test code snippets
- Create a
.htmlfile with<script>tags and open it in your browser
🧬 Real-World Analogy: Family Inheritance
Imagine a family tree. When you don't know how to do something (like cook a recipe), you ask your parent. If they don't know, they ask their parent, and so on up the family tree. In JavaScript, objects work the same way: when an object doesn't have a property or method, it "asks" its prototype, which asks its prototype, until it finds the answer or reaches the end of the chain.
Class = Blueprint (like a recipe) | Prototype = Family elder (where you inherit skills from)
📋 Prototypes vs Classes Quick Reference:
| Concept | Prototype-based | Class-based (ES6) |
|---|---|---|
| Object Creation | Object.create(proto) | new ClassName() |
| Inheritance | Prototype chain lookup | extends keyword |
| Method Sharing | Func.prototype.method | Defined inside class body |
| Under the Hood | The actual mechanism | Syntactic sugar over prototypes |
Introduction
JavaScript is one of the most misunderstood languages in the world when it comes to object-oriented programming. Developers coming from Java, Python, C#, C++, or even PHP often assume JavaScript follows the same classical inheritance model.
It does not.
JavaScript uses a prototype-based inheritance system, which is extremely flexible, dynamic, and powerful. ES6 Classes add a familiar syntax, but they are syntactic sugar—the underlying system is still prototypes all the way down.
This expert lesson will give you a true, deep, structural understanding of:
- How prototypes work
- How objects inherit properties
- What the [[Prototype]] internal slot is
- How the prototype chain is built
- Why functions have .prototype
- How ES6 Classes map onto prototypes
- How memory is shared between objects
- Real-world design patterns and architectures
1. Understanding JavaScript's Object Model
Everything in JavaScript is built on objects.
Even primitive values like strings, numbers, and booleans are temporarily wrapped in objects when you use methods on them.
Objects do not inherit from classes — they inherit from OTHER OBJECTS.
This is called prototype-based inheritance.
Every object in JavaScript has an internal hidden pointer: [[Prototype]]
This pointer links the object to another object. That other object acts as a fallback when the original object does not have a property.
const user = { name: "Alice" };
// Visually:
user ---> [[Prototype]] ---> Object.prototype ---> nullThis chain is called the prototype chain.
2. The Prototype Chain — How JavaScript Looks Up Properties
const user = { name: "Alice" };
console.log(user.toString());Does user have its own toString property? No.
So JavaScript checks:
- Does user have toString? ❌ No
- Does user.[[Prototype]] (Object.prototype) have toString? ✅ YES
- Use that one.
This system is known as: Prototype Delegation
Objects "delegate" missing behavior to their prototype.
3. Creating Objects and Their Prototypes
There are multiple ways to create objects with prototypes:
Method 1 — Object Literals
const user = { name: "Alice" };
// Prototype: Object.prototypeMethod 2 — Object.create()
const admin = Object.create(user); admin.role = "Admin"; // Now: admin ---> user ---> Object.prototype ---> null
Method 3 — Constructor Functions
function User(name) {
this.name = name;
}
// instance ---> User.prototype ---> Object.prototypeMethod 4 — ES6 Classes (Syntactic Sugar)
class User {
constructor(name) {
this.name = name;
}
}
// Behind the scenes: EXACT SAME as constructor functions + prototypes4. Functions and .prototype — Why Functions Create Objects
Every function in JavaScript automatically gets a .prototype property.
function User() {}
console.log(User.prototype); // { constructor: User }When you write:
const u = new User();
Internally:
- Create an empty object
- Set its [[Prototype]] = User.prototype
- Bind this inside User() to the new object
- Return the object
5. Building Methods on the Prototype
❌ Bad (Memory Inefficient):
function User(name) {
this.name = name;
this.sayHello = function() {
return "Hello " + this.name;
};
}
// Every instance gets its OWN copy of sayHello✅ Good (Memory Shared):
User.prototype.sayHello = function() {
return "Hello " + this.name;
};
const u1 = new User("Alice");
const u2 = new User("Bob");
u1.sayHello === u2.sayHello; // trueNow ALL instances share ONE method stored in one place.
6. ES6 Classes — Friendlier Syntax Over Prototypes
ES6 classes are syntactic sugar over the prototype system.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, I'm ${this.name}`;
}
}
const person = new Person('Alice', 30);
console.log(person.greet());Under the hood:
- Person is still a function
- Methods like greet live on Person.prototype
- new Person() sets up the prototype chain as before
Class Inheritance
Extend classes with extends and super
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
console.log(`${this.name} barks`);
}
}Static Methods
Class-level methods
class MathHelper {
static add(a, b) {
return a + b;
}
static multiply(a, b) {
return a * b;
}
}
MathHelper.add(5, 3); // 8
// Not: new MathHelper().add()Getters & Setters
Computed properties
class Circle {
constructor(radius) {
this._radius = radius;
}
get area() {
return Math.PI * this._radius ** 2;
}
set radius(value) {
if (value > 0) this._radius = value;
}
}Private Fields
True privacy with #
class BankAccount {
#balance = 0; // Private
deposit(amount) {
this.#balance += amount;
}
getBalance() {
return this.#balance;
}
}Summary: What You Learned
🎉 You are now operating at a senior-level JavaScript OOP understanding.
📋 Quick Reference — OOP in JS
| Feature | Syntax |
|---|---|
| Class | class User { ... } |
| Constructor | constructor(name) { this.name = name } |
| Inheritance | class Dog extends Animal |
| Static | static create() { ... } |
| Private | #secret = "hidden" |
Lesson 12 Complete — Prototypes & Classes!
You now understand the architecture of JavaScript objects. This is critical for understanding frameworks like React and Vue under the hood.
Up next: Design Patterns — proven architectural solutions for common coding problems! 🏗️
Sign up for free to track which lessons you've completed and get learning reminders.