JavaScript uses prototype-based inheritance. Every object has an internal link to another object called its prototype. When you access a property, JavaScript looks up the prototype chain until it finds the property or reaches null.

The Prototype Chain

  let animal = {
    eats: true,
    walk() {
        console.log('Walking...');
    }
};

let rabbit = {
    jumps: true,
    __proto__: animal // for demo; use Object.create in production
};

rabbit.walk(); // 'Walking...' — found on animal prototype
console.log(rabbit.eats); // true
  

In modern code, use Object.create or classes instead of __proto__.

Object.create

  let animal = {
    eats: true,
    walk() {
        console.log('Animal walks');
    }
};

let rabbit = Object.create(animal);
rabbit.jumps = true;

rabbit.walk(); // 'Animal walks'
  

Constructor Functions and prototype

Before ES6 classes, constructors defined shared methods on prototype:

  function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.greet = function() {
    console.log(`Hello, I'm ${this.name}`);
};

let alice = new Person('Alice', 25);
alice.greet(); // "Hello, I'm Alice"

console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
  

instanceof

Checks whether an object’s prototype chain includes a constructor’s prototype:

  console.log(alice instanceof Person); // true
console.log(alice instanceof Object);  // true
  

Classes Are Syntactic Sugar

ES6 classes are built on prototypes:

  class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    greet() {
        console.log(`Hello, I'm ${this.name}`);
    }
}

class Employee extends Person {
    constructor(name, age, role) {
        super(name, age);
        this.role = role;
    }
    describe() {
        console.log(`${this.name} is a ${this.role}`);
    }
}

let bob = new Employee('Bob', 30, 'Developer');
bob.greet();    // from Person prototype
bob.describe(); // from Employee prototype
  

Object Methods for Prototypes

  let obj = { a: 1 };
let proto = { b: 2 };

Object.getPrototypeOf(obj);           // current prototype
Object.setPrototypeOf(obj, proto);      // change prototype (use sparingly)
Object.create(proto);                   // create with given prototype

Person.prototype.hasOwnProperty('greet'); // true on instance via chain
obj.hasOwnProperty('a');              // true — own property only
  

Mixins

Combine behavior from multiple sources:

  let canEat = {
    eat() { console.log('Eating...'); }
};

let canWalk = {
    walk() { console.log('Walking...'); }
};

let person = Object.assign(Object.create(canEat), canWalk);
person.eat();
person.walk();
  

Summary

Concept Purpose
Prototype Shared methods and properties
Prototype chain Lookup path for properties
new Creates object with constructor’s prototype
class Cleaner syntax over prototypes
extends Sets up prototype chain for inheritance

Prototype inheritance is fundamental to understanding how JavaScript objects, arrays, and built-in methods work under the hood.