技术分享 2025年12月2日 约 20 分钟阅读

JavaScript 原型与原型链详解

JavaScript 是一门基于原型的语言,理解原型(Prototype)和原型链(Prototype Chain)对于深入掌握 JavaScript 至关重要。本文将带你深入了解这一核心机制。

核心概念

在 JavaScript 中,几乎所有的对象都是通过函数创建的。我们需要区分两个重要的属性:

  1. prototype: 这是函数特有的属性。它指向一个对象,这个对象包含了由该构造函数创建的实例共享的属性和方法。
  2. __proto__ (或 [[Prototype]]): 这是对象(实例)特有的属性。它指向该对象的构造函数的原型对象。

简而言之:实例.__proto__ === 构造函数.prototype

原型链的工作原理

当你访问一个对象的属性时,JavaScript 引擎会按照以下步骤查找:

  1. 首先查找对象本身是否有该属性。
  2. 如果没有,则去对象的 __proto__(即构造函数的 prototype)中查找。
  3. 如果还没有,则去 __proto____proto__ 中查找。
  4. 这个过程一直持续,直到找到 null(原型链的顶端)。

如果最终还是没找到,则返回 undefined

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

Person.prototype.sayHello = function() {
  console.log(`你好,我是 ${this.name}`);
};

const p1 = new Person('张三');

// 访问自身属性
console.log(p1.name); // "张三"

// 访问原型上的方法
p1.sayHello(); // "你好,我是 张三"

// 验证原型关系
console.log(p1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true

构造函数、原型与实例的关系

  • 构造函数: function Foo() {}
  • 原型对象: Foo.prototype
  • 实例: var f = new Foo()

它们之间的关系如下:

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

继承的实现

ES5 原型继承

在 ES6 之前,我们通常使用原型链来实现继承:

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

Animal.prototype.eat = function() {
  console.log('正在吃东西...');
};

function Dog(name) {
  Animal.call(this, '犬科'); // 借用构造函数继承实例属性
  this.name = name;
}

// 建立原型链继承方法
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor 指向

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

const myDog = new Dog('旺财');
myDog.eat(); // 继承自 Animal
myDog.bark(); // Dog 自己的方法

ES6 Class 语法糖

ES6 引入了 class 关键字,但这只是语法糖,底层的机制依然是原型链。

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

  eat() {
    console.log('正在吃东西...');
  }
}

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

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

const myDog = new Dog('来福');
myDog.eat();

总结

  • JavaScript 对象通过原型链继承属性和方法。
  • prototype 是构造函数的属性,用于定义共享的方法。
  • __proto__ 是实例的属性,指向构造函数的原型。
  • Object.prototype 是原型链的尽头,其 __proto__null
  • 理解原型链有助于编写更高效、复用性更强的代码。