Skip to main content

原型链

原型链(Prototype Chain)是 JavaScript 实现继承的核心机制,基于**原型对象(Prototype)**实现对象间的属性和方法共享。理解原型链是掌握 JS 面向对象编程的关键。

一、核心概念

1. 三个关键属性

  • prototype
    函数特有的属性,指向该函数创建的对象的原型对象
    例:Person.prototype 是所有 new Person() 创建的对象的原型。

  • __proto__
    每个对象(除 Object.prototype 外)都有的隐式属性,指向其原型对象
    例:const p = new Person(); p.__proto__ === Person.prototype

  • constructor
    原型对象的属性,指向创建该对象的构造函数
    例:Person.prototype.constructor === Person

2. 原型链的工作原理

当访问一个对象的属性/方法时,JS 会:

  1. 先在对象本身查找。
  2. 若未找到,则通过 __proto__ 逐级向上查找原型链。
  3. 直到找到属性/方法或到达 Object.prototype__proto__null)。

二、原型链结构示例

// 构造函数
function Person(name) {
this.name = name;
}

// 原型方法
Person.prototype.sayHello = function() {
return `Hello, ${this.name}`;
};

// 创建实例
const alice = new Person("Alice");

// 原型链结构:
// alice ---> Person.prototype ---> Object.prototype ---> null
  • 验证
    alice.__proto__ === Person.prototype; // true
    Person.prototype.__proto__ === Object.prototype; // true
    Object.prototype.__proto__ === null; // true

三、原型链继承

1. 基本实现

// 父类
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `${this.name} makes a sound.`;
};

// 子类
function Dog(name) {
Animal.call(this, name); // 继承实例属性
}
// 设置原型链:Dog.prototype → Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor

// 子类方法
Dog.prototype.bark = function() {
return `${this.name} barks.`;
};

// 使用
const dog = new Dog("Buddy");
dog.speak(); // "Buddy makes a sound."
dog.bark(); // "Buddy barks."

2. 原型链结构

dog ---> Dog.prototype ---> Animal.prototype ---> Object.prototype ---> null

四、原型链的问题

1. 引用类型共享问题

若原型中包含引用类型(如数组),所有实例会共享该属性:

function Person() {}
Person.prototype.hobbies = [];

const p1 = new Person();
const p2 = new Person();
p1.hobbies.push("reading");
p2.hobbies; // ["reading"](意外共享)

2. 无法向父类构造函数传参

若通过直接修改 prototype 实现继承,无法在创建子类实例时向父类传参。

五、ES6 类与原型链

ES6 的 classextends 是原型链的语法糖:

class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound.`;
}
}

class Dog extends Animal {
bark() {
return `${this.name} barks.`;
}
}

// 本质与原型链继承相同
const dog = new Dog("Buddy");
dog.__proto__ === Dog.prototype; // true
Dog.prototype.__proto__ === Animal.prototype; // true

六、原型链 vs. 其他继承方式

方式实现原理优点缺点
原型链通过 __proto__ 连接多个原型简单,自然实现多态引用类型共享,传参困难
构造函数在子类构造函数中调用父类构造实例属性独立,可传参方法无法复用
组合继承结合原型链和构造函数集两者优点父类构造函数调用两次
寄生组合优化组合继承(减少父类调用)现代 JS 推荐方式复杂度较高
ES6 类原型链的语法糖语法简洁,支持静态成员本质仍是原型链

七、原型链相关方法

1. 原型操作

  • Object.create(proto)
    创建一个新对象,指定其原型为 proto
    例:const obj = Object.create(null)(创建无原型的对象)。

  • Object.setPrototypeOf(obj, proto)
    设置对象的原型(谨慎使用,影响性能)。

2. 检查原型关系

  • instanceof
    检查对象是否属于某个类(通过原型链判断)。
    例:dog instanceof Dogtrue

  • Object.getPrototypeOf(obj)
    获取对象的原型(等同于 obj.__proto__)。

八、常见面试问题

  1. 如何实现继承?原型链继承的原理是什么?

    • 答:通过 __proto__ 连接原型对象,访问属性时逐级向上查找。
  2. instanceof 的工作原理是什么?

    • 答:检查右边构造函数的 prototype 属性是否存在于左边对象的原型链中。
  3. 如何判断一个属性是对象自身的还是原型链上的?

    • 答:使用 obj.hasOwnProperty(key)(仅检查自身属性)。

九、总结

  • 原型链是 JS 继承的核心机制,通过 __proto__ 连接多个原型对象,实现属性和方法的共享。
  • ES6 类本质上仍是基于原型链,但提供了更简洁的语法。
  • 理解原型链是掌握 JS 高级特性的基础,包括 this 指向、闭包、框架原理等。