stackademic

The leading education platform for anyone with an interest in software development.

JavaScript Prototypes

Understand prototype chains, inheritance, and how property lookup works

Overview

Every JavaScript object has an internal link to another object called its prototype, forming a chain that ends at null. When you read a property, the engine walks this chain until it finds a match or gives up. Classes are largely syntactic sugar over this prototype mechanism.

Syntax / Usage

Use Object.create to set a prototype directly, Object.getPrototypeOf to inspect it, and constructor functions or class to share methods via prototype.

const animal = {
  describe() {
    return `${this.name} makes a sound`
  },
}

const dog = Object.create(animal) // dog's prototype is animal
dog.name = 'Rex'
console.log(dog.describe()) // 'Rex makes a sound'

console.log(Object.getPrototypeOf(dog) === animal) // true
console.log(dog.hasOwnProperty('name')) // true
console.log(dog.hasOwnProperty('describe')) // false (inherited)

Examples

Constructor functions attach shared methods to prototype, so instances reuse one copy:

function Point(x, y) {
  this.x = x
  this.y = y
}

Point.prototype.distanceTo = function (other) {
  return Math.hypot(this.x - other.x, this.y - other.y)
}

const a = new Point(0, 0)
const b = new Point(3, 4)
console.log(a.distanceTo(b)) // 5

class syntax produces the same prototype chain under the hood:

class Shape {
  constructor(name) {
    this.name = name
  }
  describe() {
    return `a ${this.name}`
  }
}

class Circle extends Shape {
  constructor(r) {
    super('circle')
    this.r = r
  }
  area() {
    return Math.PI * this.r ** 2
  }
}

const c = new Circle(2)
console.log(c.describe(), c.area().toFixed(2)) // 'a circle' '12.57'
console.log(Object.getPrototypeOf(Circle.prototype) === Shape.prototype) // true

Common Mistakes

  • Mutating a shared prototype at runtime, affecting every instance unexpectedly
  • Using __proto__ in performance-sensitive code instead of Object.getPrototypeOf
  • Forgetting new, so this binds to the global object or is undefined
  • Storing mutable state (like arrays) on the prototype, accidentally sharing it across instances
  • Confusing instanceof (checks the chain) with hasOwnProperty (checks own keys)

See Also

objects functions javascript-proxies-reflect