Classes and Prototypes
Classes look different from constructor functions, but they still use prototypes.
This is important:
JavaScript classes are syntax built on top of the prototype system.Understanding this helps explain where class methods live and how inheritance works.
Class Methods Live on the Prototype
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
const user = new User("Alice");
console.log(Object.hasOwn(user, "name")); // true
console.log(Object.hasOwn(user, "greet")); // false
console.log(Object.hasOwn(User.prototype, "greet")); // truename is stored directly on the instance.
greet is stored on User.prototype.
Instance Prototype Link
const user = new User("Alice");
console.log(Object.getPrototypeOf(user) === User.prototype); // trueThe instance inherits from the class prototype.
Prototype chain:
user
-> User.prototype
-> Object.prototype
-> nullClass Inheritance and Prototypes
class Animal {
speak() {
return "Animal sound";
}
}
class Dog extends Animal {
bark() {
return "Woof";
}
}
const dog = new Dog();
console.log(dog.bark()); // Woof
console.log(dog.speak()); // Animal sounddog inherits from Dog.prototype.
Dog.prototype inherits from Animal.prototype.
Prototype chain:
dog
-> Dog.prototype
-> Animal.prototype
-> Object.prototype
-> nullStatic Methods and Prototypes
Instance methods live on ClassName.prototype.
Static methods live on the class constructor itself.
class User {
greet() {
return "Hello";
}
static createGuest() {
return new User();
}
}
console.log(Object.hasOwn(User.prototype, "greet")); // true
console.log(Object.hasOwn(User, "createGuest")); // trueThat is why you call:
user.greet();and:
User.createGuest();Public Fields Are Own Properties
Modern public fields become own properties on each instance.
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const counter = new Counter();
console.log(Object.hasOwn(counter, "count")); // true
console.log(Object.hasOwn(counter, "increment")); // falsecount is on the instance.
increment is on the prototype.
Arrow Function Fields Are Own Properties
Some code uses arrow function fields in classes.
class User {
name = "Alice";
greet = () => {
return `Hello, ${this.name}`;
};
}
const a = new User();
const b = new User();
console.log(Object.hasOwn(a, "greet")); // true
console.log(a.greet === b.greet); // falseThe arrow function is created for each instance.
This can preserve this, but it is not shared through the prototype.
Use this pattern intentionally.
Do Not Modify Built-In Prototypes
Avoid adding methods to built-in prototypes.
Array.prototype.last = function () {
return this[this.length - 1];
};This may seem convenient, but it can cause problems:
- conflicts with future JavaScript features
- conflicts with libraries
- surprising behavior in loops or debugging
- harder-to-maintain code
Prefer helper functions:
function last(array) {
return array[array.length - 1];
}Or use existing methods:
array.at(-1);Prototype Pollution Awareness
Prototype pollution is when code accidentally or maliciously changes a shared prototype such as Object.prototype.
Object.prototype.isAdmin = true;Now many objects may appear to have isAdmin.
const user = {};
console.log(user.isAdmin); // trueThis can create serious security bugs.
You will study security later.
For now:
Do not modify Object.prototype or other built-in prototypes.Best Practices
Use classes for modern object-oriented code.
Remember that class methods are prototype methods.
Use Object.hasOwn() to distinguish own properties from inherited ones.
Avoid modifying built-in prototypes.
Use public fields for simple instance defaults.
Use normal class methods for shared behavior.
Use arrow function fields only when you specifically need per-instance bound behavior.
Common Mistakes
Mistake 1: Thinking Class Syntax Avoids Prototypes
Classes are built on prototypes.
They make prototype-based object creation easier to write.
Mistake 2: Expecting Methods to Be Own Properties
class User {
greet() {}
}
const user = new User();
Object.hasOwn(user, "greet"); // falseThe method is on User.prototype.
Mistake 3: Modifying Object.prototype
Object.prototype.extra = "bad idea";This affects many objects.
Avoid it.
Summary
Classes and prototypes are connected.
- Class methods live on
ClassName.prototype. - Instances inherit from the class prototype.
extendscreates a prototype chain between class prototypes.- Static methods live on the class constructor.
- Public fields become own properties on each instance.
- Arrow function fields are per-instance functions.
- Avoid modifying built-in prototypes.
- Prototype knowledge explains how class behavior is shared.