Technical Sharing December 2, 2025 约 24 分钟阅读

Deep Dive into JavaScript Prototypes and Prototype Chains

JavaScript is a prototype-based language. Understanding Prototypes and the Prototype Chain is crucial for mastering JavaScript. This article will take you deep into this core mechanism.

Core Concepts

In JavaScript, almost all objects are created by functions. We need to distinguish between two important properties:

  1. prototype: This is a property specific to functions. It points to an object that contains properties and methods shared by instances created by that constructor function.
  2. __proto__ (or [[Prototype]]): This is a property specific to objects (instances). It points to the prototype object of the constructor that created the object.

In short: instance.__proto__ === Constructor.prototype

How the Prototype Chain Works

When you access a property of an object, the JavaScript engine looks it up in the following order:

  1. First, it checks if the object itself has the property.
  2. If not, it looks in the object's __proto__ (i.e., the constructor's prototype).
  3. If still not found, it looks in the __proto__ of that __proto__.
  4. This process continues until it reaches null (the end of the prototype chain).

If it's still not found, it returns undefined.

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

Person.prototype.sayHello = function() {
  console.log(`Hello, I am ${this.name}`);
};

const p1 = new Person('Alice');

// Accessing own property
console.log(p1.name); // "Alice"

// Accessing method on prototype
p1.sayHello(); // "Hello, I am Alice"

// Verifying prototype relationship
console.log(p1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true

Relationship between Constructor, Prototype, and Instance

  • Constructor: function Foo() {}
  • Prototype Object: Foo.prototype
  • Instance: var f = new Foo()

Their relationship is as follows:

  • f.__proto__ === Foo.prototype
  • Foo.prototype.constructor === Foo

Implementing Inheritance

ES5 Prototype Inheritance

Before ES6, we usually used the prototype chain to implement inheritance:

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

Animal.prototype.eat = function() {
  console.log('Eating...');
};

function Dog(name) {
  Animal.call(this, 'Canine'); // Borrow constructor to inherit instance properties
  this.name = name;
}

// Establish prototype chain for method inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // Fix constructor pointer

Dog.prototype.bark = function() {
  console.log('Woof!');
};

const myDog = new Dog('Buddy');
myDog.eat(); // Inherited from Animal
myDog.bark(); // Dog's own method

ES6 Class Syntax Sugar

ES6 introduced the class keyword, but it is just syntactic sugar; the underlying mechanism is still the prototype chain.

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

  eat() {
    console.log('Eating...');
  }
}

class Dog extends Animal {
  constructor(name) {
    super('Canine');
    this.name = name;
  }

  bark() {
    console.log('Woof!');
  }
}

const myDog = new Dog('Max');
myDog.eat();

Summary

  • JavaScript objects inherit properties and methods through the prototype chain.
  • prototype is a property of the constructor function, used to define shared methods.
  • __proto__ is a property of the instance, pointing to the constructor's prototype.
  • Object.prototype is the end of the prototype chain, and its __proto__ is null.
  • Understanding the prototype chain helps in writing more efficient and reusable code.