JavaScript 中的五种继承方式进行深入对比

发布于:2025-05-20 ⋅ 阅读:(21) ⋅ 点赞:(0)


前言

对 JavaScript 中的五种继承方式进行深入对比:原型链继承、构造函数继承、组合继承、寄生组合继承、以及 ES6 的 class extends。

内容将包括:

  • 每种方式的定义与核心原理
  • 示例代码
  • 优点与缺点分析
  • 应用场景与现代推荐

我整理好结构化的对比表格与说明文档后会立即通知你查看。

JavaScript 五种继承方式对比

JavaScript 的继承机制本质上是通过“原型链”将父类和子类关联起来。在 ES6 出现之前,开发者总结出了多种继承的经典实现方式,包括原型链继承构造函数继承组合继承寄生组合继承,以及 ES6 引入的 class extends 继承。下面将逐一分析这五种继承方式的实现原理、示例代码、优缺点(围绕属性共享、方法复用、实例隔离等方面),并给出适用场景建议。最后,我们提供一个对比表格,清晰展示这些方式在语法复杂度、性能、兼容性和多继承支持方面的差异。

原型链继承

实现原理与机制: 将子类的原型对象指向父类的一个实例,从而使子类实例的原型链上含有父类实例和父类的原型。这样,子类实例在访问属性或方法时,如果自身不存在,会沿着原型链在父类实例以及父类原型上查找,从而继承父类的属性和方法。

示例代码: 子类的原型指向父类实例,实现继承。注意此方式不调用父类构造函数,因此不能传参,也不会为每个子实例单独初始化父类属性。

function Parent() {
   
  this.name = "Parent";
  this.colors = ["red", "blue"];    // 引用类型属性
}
Parent.prototype.getName = function() {
   
  console.log("Name: " + this.name);
};

function Child() {
   
  this.name = "Child";
}
// 子类原型指向父类实例,实现原型链继承
Child.prototype = new Parent();
Child.prototype.constructor = Child;  // (可选)修正constructor指向

const child1 = new Child();
const child2 = new Child();
child1.colors.push("green");  
console.log(child1.colors, child2.colors);  // 输出: ["red","blue","green"] ["red","blue","green"] 
// 两个实例的 colors 引用同一个数组,修改一个会影响另一个
child1.getName();  // 输出: Name: Child
console.log(child1.getName === child2.getName);  // 输出: true (方法共享)

优点:

  • 子类通过原型链可以访问父类原型上的所有属性和方法,实现方法复用,共享父类的功能。如果父类原型新增方法/属性,子类实例也能访问到,维护成本低。
  • 实现简单,只需一行设置原型链,符合 JavaScript 原型继承的直观模型。

缺点:

  • 无法传参: 在创建子类实例时不能向父类构造函数传递参数(因为根本没有调用父构造函数)。每个子类实例无法定制父类初始化过程。
  • 引用属性共享: 父类构造函数里的引用类型属性(如数组、对象)会被所有子类实例共享,因为这些属性存在于同一个父类实例(即子类的原型对象)上。这导致实例不隔离 —— 一个实例修改了这些共享属性,会影响其他实例。上例中两个子实例的 colors 就指向同一数组。
  • 父类构造函数未在子类实例上执行,子类实例可能缺少父类构造函数中初始化的各自独立的属性值。如需每个实例拥有自己的副本,则无能为力。

适用场景: 原型链继承在需要共享方法且父类仅包含方法或静态属性时有用。但由于无法传参且存在引用属性共享问题,实际开发中很少单独使用。若父类含需单独初始化的属性(特别是引用类型),应考虑其他继承方式或在继承后手动屏蔽/重写这些属性。

构造函数继承

实现原理与机制: 在子类构造函数内部调用父类构造函数(通常使用 Parent.call(this, ...)apply),并将子类实例的 this 绑定给父类构造函数。这样,父类构造函数中定义的属性都会添加到子类实例上,实现对父类属性的继承。这种方式又称“借用构造函数”继承。

示例代码: 子类构造函数内部借用父类构造函数。由于没有建立原型链关系,父类原型方法不会自动继承下来。

function Parent(name) {
   
  this.name = name;
  this.colors = ["red", "blue"];  // 引用类型属性
}
Parent

网站公告

今日签到

点亮在社区的每一天
去签到