详解JavaScript实现继承的五种经典方式(附图解)

作者:纸飞机时间:2026-10-30 22:50:16浏览:92

本文详细解析JavaScript中实现继承的五种经典方式,包括原型链继承、构造函数继承、组合继承、原型式继承以及ES6类继承。通过图解和代码示例,深入探讨每种方式的实现原理、优缺点及适用场景,帮助开发者理解并选择合适的继承策略。

引言

  • 在 JavaScript 中,实现继承的几种常见方式包括:
      1. 原型链继承:该模式包含两种具体实现路径
      • 1.1 共用同一父类实例
      • 1.2 跳过父类实例,共用同一类型原型
      1. 构造函数继承(又称借用构造函数)
      1. 组合继承
      1. 原型式继承
      1. ES6 类继承机制

原型链继承详解

原型链继承-共用同一父类实例

此为 JavaScript 最早的继承手段,通过令子类原型对象指向父类实例,达成子类对父类属性与方法的继承。其弊端在于所有子类实例将共用同一个父类实例。

function Parent() {
  this.property = "parentProperty";
}
Parent.prototype.say = function () {
  console.log("Parent say");
};
function Child() {
  this.childProperty = "childProperty";
}
// 修改 Child 的 prototype 属性指向 Parent 实例对象,那么 Child 实例对象的 __proto__ 就会指向其构造函数 Child 的 prototype 属性(即Parent 实例对象)
// 修改了 Child.prototype 的指向后,那么原来 Child.prototype 指向的对象由于被没有引用,就会被回收。
Child.prototype = new Parent();
const childInstance = new Child();
console.log(childInstance.property); // 输出 'parentProperty'
childInstance.say();

代码逻辑图解如下:

引言

上述代码表面无误,实则隐含缺陷:

console.log(Child.prototype.constructor); // 输出:[Function: Parent], 即是 Parent 构造函数,这是由于 Child.prototype 自身没有,就会沿着 __proto__ 寻找,因此找到 Parent。这明显是不对的
console.log(Child.prototype.constructor === Child); // 输出:false, 这明显也是不对的

故在修正 Child.prototype 指向后(即执行代码 Child.prototype = new Parent(); ),须同步修正 Child.prototype.constructor 指向:

Child.prototype = new Parent();
+Child.prototype.constructor = Child;
  • 后续代码逻辑亦遵循此原则!

原型链继承-跳过父类实例,共用父类原型

function Parent() {
  this.property = "parentProperty";
}
Parent.prototype.say = function () {
  console.log("Parent say");
};
function Child() {
  Parent.call(this);
  this.childProperty = "childProperty";
}
// 方式一:直接指向
// Child.prototype.__proto__ = Parent.prototype;
// 方式二:使用 Object.create(),这是 es5 的方法
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
let childInstance = new Child();
console.log(childInstance.property);
childInstance.say();

代码逻辑图解如下:

引言

构造函数继承(借用构造函数)

此法通过在子类构造函数内调用父类构造函数以继承属性。由此确保各子类实例拥有独立属性副本,然无法继承父类原型上的方法。

function Parent() {
  this.property = "parentProperty";
}
Parent.prototype.say = function () {
  console.log("Parent say");
};
function Child() {
  Parent.call(this);
  this.childProperty = "childProperty";
}
const childInstance = new Child();
console.log(childInstance.property); // 输出 'parentProperty'
// childInstance.say() // 报错:childInstance.say is not a function

代码逻辑图解如下:

引言

组合继承

组合继承融合原型链与构造函数继承,通过在子类构造函数中调用父类构造函数,并将子类原型设为父类实例,实现属性与方法的双重继承。

function Parent() {
  this.property = "parentProperty";
}
Parent.prototype.say = function () {
  console.log("Parent say");
};
function Child() {
  Parent.call(this);
  this.childProperty = "childProperty";
}
Child.prototype = new Parent();
// 注意:修改其原型对象之后,同时必须得修改 constructor 的指向
Child.prototype.constructor = Child;
const childInstance = new Child();
console.log(childInstance.property); // 输出 'parentProperty'
childInstance.say();

引言

原型式继承

此方式构建临时构造函数,将其原型指向父构造函数原型,再将子构造函数原型指向该临时构造函数的实例,以此达成继承。

function mockExtend(Parent, Child) {
  function Fn() {}
  /**
   * 1. 修改了 Fn.prototype 的指向后,那么原来的 Fn.prototype 没有被引用,则会被回收
   * 2. 那么Fn的实例对象的 __proto__ 就指向其构造函数的 prototype
   */
  Fn.prototype = Parent.prototype;
  Child.prototype = new Fn();
  // 注意:修改了原型对象之后,同时必须得修改 constructor 的指向
  Child.prototype.constructor = Child;
}
// =============================== 使用 ==================================
function Parent() {
  this.property = "parentProperty";
}
Parent.prototype.say = function () {
  console.log("Parent say");
};
function Child() {
  Parent.call(this);
  this.childProperty = "childProperty";
}
mockExtend(Parent, Child);
const childInstance = new Child();
console.log(childInstance.property);
childInstance.say();

代码逻辑图解如下:

引言

ES6 类继承

ES6 引入 class 关键字,使继承机制更直观易用。借助 extends 关键字,类可继承另一类的属性与方法。

class Parent {
  constructor() {
    this.property = "parentProperty";
  }
  say() {
    console.log("Parent say");
  }
}
class Child extends Parent {
  constructor() {
    super();
    this.childProperty = "childProperty";
  }
}
const childInstance = new Child();
console.log(childInstance.property); // 输出 'parentProperty'
childInstance.say();

至此,关于详解 JavaScript 实现继承的五种经典方式(附图解)的文章介绍完毕,更多相关 JavaScript 实现继承方式内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章