JavaScript Prototypes

JavaScript Prototypes

Prototypes are the foundation of JavaScript’s object system. Every object has a prototype, forming a chain that JavaScript uses to look up properties and methods. Understanding prototypes is key to mastering JavaScript inheritance.

What Are Prototypes?

Every JavaScript object has a hidden [[Prototype]] property that links to another object. This creates a prototype chain for property lookup.

let person = {
  name: 'Alice',
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

console.log(person.name); // 'Alice' (own property)
console.log(person.toString); // function (inherited from Object.prototype)

The Prototype Chain

When you access a property, JavaScript:

  1. Checks the object itself
  2. If not found, checks the object’s prototype
  3. Continues up the chain until Object.prototype
  4. If still not found, returns undefined
let animal = {
  eats: true,
  walk() {
    console.log('Animal walks');
  }
};

let dog = Object.create(animal); // dog.__proto__ = animal
dog.barks = true;

console.log(dog.eats); // true (from animal)
console.log(dog.barks); // true (own property)
dog.walk(); // 'Animal walks' (from animal)

Constructor Functions

Before ES6 classes, we used constructor functions:

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

// Add methods to prototype
Person.prototype.greet = function() {
  console.log(`Hi, I'm ${this.name}`);
};

let person1 = new Person('Alice', 30);
let person2 = new Person('Bob', 25);

person1.greet(); // 'Hi, I'm Alice'

All instances share the same prototype methods, saving memory.

Accessing Prototypes

Use __proto__ or Object.getPrototypeOf():

let arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype); // true
console.log(Object.getPrototypeOf(arr) === Array.prototype); // true

Setting Prototypes

Use Object.setPrototypeOf() or __proto__:

let animal = { eats: true };
let dog = { barks: true };

Object.setPrototypeOf(dog, animal);
// or dog.__proto__ = animal;

console.log(dog.eats); // true

Prototype Inheritance

Create inheritance chains:

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

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound`);
};

function Dog(name, breed) {
  Animal.call(this, name); // Call parent constructor
  this.breed = breed;
}

// Set up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
  console.log(`${this.name} barks`);
};

let dog = new Dog('Buddy', 'Golden Retriever');
dog.speak(); // 'Buddy barks'

Modern Inheritance

ES6 classes use prototypes under the hood:

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`);
  }
}

This compiles to prototype-based code.

Checking Property Ownership

Use hasOwnProperty() to check if a property is own or inherited:

let obj = { ownProp: 'value' };
obj.__proto__ = { inheritedProp: 'inherited' };

console.log(obj.ownProp); // 'value'
console.log(obj.inheritedProp); // 'inherited'
console.log(obj.hasOwnProperty('ownProp')); // true
console.log(obj.hasOwnProperty('inheritedProp')); // false

Prototype Methods

Common prototype methods:

  • Object.create(proto) - Create object with specific prototype
  • Object.getPrototypeOf(obj) - Get prototype
  • Object.setPrototypeOf(obj, proto) - Set prototype
  • obj.isPrototypeOf(instance) - Check if obj is in prototype chain
let parent = { value: 42 };
let child = Object.create(parent);

console.log(parent.isPrototypeOf(child)); // true
console.log(Object.getPrototypeOf(child) === parent); // true

Performance Considerations

Prototype lookups are fast, but deep chains can slow things down. Keep inheritance shallow.

Modifying prototypes affects all instances:

function Car(model) {
  this.model = model;
}

let car1 = new Car('Toyota');
let car2 = new Car('Honda');

Car.prototype.drive = function() {
  console.log(`${this.model} is driving`);
};

car1.drive(); // 'Toyota is driving'
car2.drive(); // 'Honda is driving'

Prototypes are the core of JavaScript’s object model. Classes are just syntax on top of prototypes.

For more on classes, see JavaScript classes.

The MDN Prototypes guide is excellent for deeper understanding.

Last updated on