DNA⚡ JavaScriptPrototypes & Inheritance
ðŸĢHatchlingJavaScriptFundamentalsOOP

Prototypes & Inheritance

JavaScript's prototype chain is the engine beneath classes, Object.create, and half the 'magic' in the language. Master the mental model interviewers expect.

Prototypes & Inheritance

If someone asks you "how does inheritance work in JavaScript?" and you jump straight to class extends, you've shown them you learned syntax, not the language.

The Prototype Chain

Every JavaScript object has an internal [[Prototype]] link to another object. When you access a property that doesn't exist on the object, the engine walks up this chain until it finds the property or hits null.

const animal = { eats: true };
const rabbit = Object.create(animal);
rabbit.jumps = true;
 
rabbit.jumps; // true — own property
rabbit.eats;  // true — found on prototype
rabbit.toString(); // found on Object.prototype

The chain: rabbit → animal → Object.prototype → null

Object.create vs Constructor Functions

Object.create sets the prototype directly — no constructor invocation, no new:

const proto = {
  greet() {
    return `Hello, ${this.name}`;
  },
};
 
const user = Object.create(proto);
user.name = 'Alex';
user.greet(); // "Hello, Alex"

Constructor functions do the same thing but with ceremony:

function User(name) {
  this.name = name;
}
User.prototype.greet = function () {
  return `Hello, ${this.name}`;
};
 
const user = new User('Alex');
// user.[[Prototype]] === User.prototype

new does four things: creates an empty object, sets its prototype to Constructor.prototype, binds this, and returns the object (unless the constructor returns an object explicitly).

Classes Are Syntactic Sugar

ES6 classes compile down to constructor functions and prototype assignment:

class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    return `${this.name} makes a sound`;
  }
}
 
// Equivalent to:
// Animal.prototype.speak = function() { ... }

extends sets up a two-level prototype chain:

class Dog extends Animal {
  bark() {
    return `${this.name} barks`;
  }
}
 
// Dog.prototype.[[Prototype]] === Animal.prototype
// Dog.[[Prototype]] === Animal (for static inheritance)

Where Prototypes Bite You

Property shadowing

const parent = { items: [1, 2, 3] };
const child = Object.create(parent);
 
child.items.push(4);
parent.items; // [1, 2, 3, 4] — mutation, not shadowing

Reading child.items walks the chain and returns the same array reference. Mutation affects the prototype. To shadow, you'd need child.items = [...parent.items, 4].

instanceof checks the chain, not the constructor

const obj = Object.create(Array.prototype);
obj instanceof Array; // true — but obj is NOT an array
Array.isArray(obj);   // false

instanceof walks [[Prototype]] looking for Constructor.prototype. It can be fooled.

Interview Patterns

"Implement classical inheritance without class" — they want to see you wire up prototypes manually:

function Shape(x, y) {
  this.x = x;
  this.y = y;
}
Shape.prototype.move = function (dx, dy) {
  this.x += dx;
  this.y += dy;
};
 
function Circle(x, y, r) {
  Shape.call(this, x, y); // super() equivalent
  this.radius = r;
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
Circle.prototype.area = function () {
  return Math.PI * this.radius ** 2;
};

"What's the difference between __proto__ and prototype?"

  • prototype is a property on functions — it becomes the [[Prototype]] of instances created with new.
  • __proto__ (deprecated, use Object.getPrototypeOf) is the accessor for an object's internal [[Prototype]] link.

Senior-Level Signal

In interviews, demonstrate that you understand prototypes as a delegation mechanism, not a copy mechanism. JavaScript doesn't copy methods from parent to child — it delegates lookups up the chain at runtime. This is fundamentally different from classical inheritance in Java or C++, and it's why mixins, composition, and Object.assign are natural patterns in JS.