⚡ Lesson 18 of 30
Prototypes & Inheritance
Understand the prototype chain, Object.create, and how ES6 classes relate to prototype-based inheritance.
The Prototype Chain
Every object has an internal [[Prototype]] link. When you access a property, JavaScript walks up the chain:
const arr = [1, 2, 3];
// arr.__proto__ === Array.prototype
// Array.prototype.__proto__ === Object.prototype
console.log(arr.hasOwnProperty("length")); // true
console.log(arr.hasOwnProperty("map")); // false (inherited)
console.log("map" in arr); // true (chain lookup)
Object.create
Create an object with a specific prototype:
const animal = {
breathe() { console.log("Breathing..."); }
};
const dog = Object.create(animal);
dog.bark = function() { console.log("Woof!"); };
dog.bark(); // "Woof!" (own method)
dog.breathe(); // "Breathing..." (from prototype)
Constructor Functions (Pre-ES6)
Before classes, constructor functions with new were used:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`;
};
const alice = new Person("Alice", 30);
console.log(alice.greet()); // "Hi, I'm Alice"
console.log(alice instanceof Person); // true
class vs prototype
ES6 classes are syntactic sugar over prototypal inheritance:
class Person {
constructor(name) { this.name = name; }
greet() { return `Hi, I'm ${this.name}`; }
}
// Under the hood:
// Person.prototype.greet = function() {...}
console.log(typeof Person); // "function"
console.log(Object.getPrototypeOf(Person.prototype) === Object.prototype);
Mixins Pattern
JavaScript doesn't have multiple inheritance, but mixins simulate it:
const Serializable = (Base) => class extends Base {
serialize() { return JSON.stringify(this); }
};
const Timestamped = (Base) => class extends Base {
get created() { return new Date().toISOString(); }
};
class User extends Timestamped(Serializable(class{})) {
constructor(name) { super(); this.name = name; }
}
const u = new User("Alice");
console.log(u.serialize()); // '{"name":"Alice"}'