🔗

Prototypes

intermediate

Prototypes are JavaScript's mechanism for inheritance. Every object has a hidden [[Prototype]] link to another object. When you access a property, JS looks up the prototype chain until it finds it or reaches null.

🎮Interactive Visualization

Look up:
Heap Memory (Prototype Chain)
dog
name:"Rex"
bark:fn()
__proto__: → Animal.prototype
↓ __proto__
Animal.prototype
speak:fn()
eat:fn()
__proto__: → Object.prototype
↓ __proto__
Object.prototype
toString:fn()
hasOwnProperty:fn()
__proto__: → null
↓ __proto__
null
End of chain
Key Insight: Prototype Chain: JS walks up __proto__ links until it finds the property or hits null.

Key Points

  • Every object has a [[Prototype]] (accessible via __proto__ or Object.getPrototypeOf)
  • Property lookup walks up the prototype chain
  • Functions have a .prototype property used for constructor instances
  • Object.create() creates objects with a specific prototype
  • ES6 classes are syntactic sugar over prototypes

💻Code Examples

Basic Prototype Chain

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

const dog = {
  barks: true
};

dog.__proto__ = animal;

dog.barks;  // true (own property)
dog.eats;   // true (from prototype)
dog.walk(); // "Walking" (from prototype)

JS walks up __proto__ links to find properties

Simple Object Literal

const obj = { x: 1 };

// All objects inherit from Object.prototype
obj.__proto__ === Object.prototype  // true

// That's why we can use:
obj.toString();      // "[object Object]"
obj.hasOwnProperty("x");  // true

// These methods come from Object.prototype

Object literals inherit from Object.prototype

Object.create()

const parent = {
  greet() {
    console.log("Hello from " + this.name);
  }
};

const child = Object.create(parent);
child.name = "Child";

child.greet();  // "Hello from Child"

// Object.create() sets the prototype
Object.getPrototypeOf(child) === parent  // true

Create object with specific prototype

Property Shadowing

const parent = {
  name: "Parent",
  greet() {
    return "Hi from " + this.name;
  }
};

const child = Object.create(parent);
child.name = "Child";  // shadows parent.name

child.greet();  // "Hi from Child"

// child.name shadows parent.name
// but greet() is still from parent

Child property hides parent property

Constructor Function

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

Person.prototype.greet = function() {
  console.log("Hi, I'm " + this.name);
};

const alice = new Person("Alice");
const bob = new Person("Bob");

alice.greet();  // "Hi, I'm Alice"
bob.greet();    // "Hi, I'm Bob"

// Both share the same greet method!
alice.greet === bob.greet  // true

Instances inherit from Constructor.prototype

hasOwnProperty Check

const parent = { inherited: true };
const child = Object.create(parent);
child.own = true;

// hasOwnProperty: only own properties
child.hasOwnProperty("own");       // true
child.hasOwnProperty("inherited"); // false

// 'in' operator: checks entire chain
"own" in child;        // true
"inherited" in child;  // true

// Useful for safe iteration
for (let key in child) {
  if (child.hasOwnProperty(key)) {
    console.log(key);  // only "own"
  }
}

hasOwnProperty checks only object, "in" checks chain

Object.create(null)

// Normal object has prototype
const normal = {};
normal.toString;  // [Function]

// Null prototype = truly empty
const dict = Object.create(null);
dict.toString;    // undefined

// Safe dictionary (no collisions)
dict["hasOwnProperty"] = "safe!";
dict.hasOwnProperty;  // "safe!"

// With normal object this would
// shadow the built-in method

No prototype = no inherited methods, safe dictionaries

Class Syntax (ES6)

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + " makes a sound");
  }
}

class Dog extends Animal {
  speak() {
    console.log(this.name + " barks");
  }
}

const dog = new Dog("Rex");
dog.speak();  // "Rex barks"

// Classes are syntactic sugar!
// Under the hood: prototypes

Classes are syntactic sugar over prototypes

Common Mistakes

  • Confusing __proto__ with .prototype
  • Modifying Object.prototype (affects all objects!)
  • Not understanding that arrays/functions are also objects with prototypes

Interview Tips

  • Draw the prototype chain for a given object
  • Explain the difference between __proto__ and .prototype
  • Know how ES6 classes relate to prototypes

🔗Related Concepts