JavaScript继承的实现方式详解

 更新时间:2025年03月23日 15:56:09   作者:Peter-Lu  
JavaScript 是一门基于原型的语言,它的继承机制与传统的基于类的面向对象编程有所不同,尽管 ES6 引入了 class 语法,但本质上仍然是基于原型链的继承,本文将详细介绍 JavaScript 继承的几种实现方式,需要的朋友可以参考下

引言

JavaScript 是一门基于原型的语言,它的继承机制与传统的基于类的面向对象编程(如 Java、C++)有所不同。尽管 ES6 引入了 class 语法,但本质上仍然是基于原型链的继承。本文将详细介绍 JavaScript 继承的几种实现方式,包括原型链继承、构造函数继承、组合继承、寄生组合继承,以及 ES6 class 继承,并分析它们的优缺点和适用场景。

一、JavaScript 继承的基本概念

在 JavaScript 中,每个对象都有一个原型(prototype),新创建的对象可以从原型对象继承属性和方法。继承的核心思想是:子类对象可以访问父类的属性和方法,从而实现代码复用。

JavaScript 主要提供了以下几种继承方式:

  1. 原型链继承
  2. 构造函数继承
  3. 组合继承(构造函数 + 原型链)
  4. 寄生组合继承(最优方案)
  5. ES6 class 继承

接下来,我们将逐一介绍这些继承方式的实现原理、代码示例以及优缺点。

二、原型链继承

1. 实现方式

原型链继承的核心思想是让子类的 prototype 指向父类的实例,这样子类就能访问父类的方法和属性。

function Parent() {
  this.name = "Parent";
  this.colors = ["red", "blue", "green"];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child() {}

Child.prototype = new Parent(); // 关键点:让子类的 prototype 指向父类实例

const child1 = new Child();
console.log(child1.getName()); // Parent
console.log(child1.colors); // ["red", "blue", "green"]

child1.colors.push("yellow");

const child2 = new Child();
console.log(child2.colors); // ["red", "blue", "green", "yellow"] (被修改了)

2. 存在的问题

  • 子类实例共享父类的引用属性:修改 child1.colors 之后,child2.colors 也会受到影响,因为 colors 是父类实例的属性,所有子类实例都共享同一个对象。
  • 无法向父类构造函数传参:创建子类实例时,无法向 Parent 传递参数。

三、构造函数继承

1. 实现方式

通过在子类的构造函数中调用父类构造函数,并使用 call() 或 apply() 绑定 this,从而避免原型链继承的问题。

function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}

function Child(name) {
  Parent.call(this, name); // 关键点:在子类构造函数中调用父类构造函数
}

const child1 = new Child("Child1");
const child2 = new Child("Child2");

child1.colors.push("yellow");

console.log(child1.colors); // ["red", "blue", "green", "yellow"]
console.log(child2.colors); // ["red", "blue", "green"] (不会被修改)

2. 解决的问题

  • ✅ 避免了引用属性共享问题(子类实例有自己的 colors
  • ✅ 支持向父类构造函数传参

3. 存在的问题

  • 方法不能复用:父类的方法必须在每个子类实例上都创建一次,而不是共享在 prototype 上。

四、组合继承(构造函数 + 原型链)

1. 实现方式

组合继承结合了构造函数继承原型链继承的优点。

function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name); // 调用父类构造函数,继承实例属性
  this.age = age;
}

Child.prototype = new Parent(); // 继承父类方法
Child.prototype.constructor = Child; // 修正 constructor 指向

const child1 = new Child("Child1", 18);
console.log(child1.getName()); // Child1
console.log(child1.colors); // ["red", "blue", "green"]

2. 解决的问题

  • ✅ 避免了引用属性共享问题
  • ✅ 支持传参
  • ✅ 方法可以复用

3. 存在的问题

  • 方法不能复用:父类的方法必须在每个子类实例上都创建一次,而不是共享在 prototype 上。

四、组合继承(构造函数 + 原型链)

1. 实现方式

组合继承结合了构造函数继承原型链继承的优点。

function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name); // 调用父类构造函数,继承实例属性
  this.age = age;
}

Child.prototype = new Parent(); // 继承父类方法
Child.prototype.constructor = Child; // 修正 constructor 指向

const child1 = new Child("Child1", 18);
console.log(child1.getName()); // Child1
console.log(child1.colors); // ["red", "blue", "green"]

2. 解决的问题

  • ✅ 避免了引用属性共享问题
  • ✅ 支持传参
  • ✅ 方法可以复用

3. 存在的问题

  • 父类构造函数被调用了两次(一次在 Parent.call(this, name),一次在 new Parent())。

五、寄生组合继承(推荐方案)

1. 实现方式

寄生组合继承优化了组合继承中的 new Parent(),避免了父类构造函数的重复调用。

function Parent(name) {
  this.name = name;
  this.colors = ["red", "blue", "green"];
}

Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name); // 继承属性
  this.age = age;
}

Child.prototype = Object.create(Parent.prototype); // 继承方法,但不会执行 Parent 构造函数
Child.prototype.constructor = Child; // 修正 constructor 指向

const child1 = new Child("Child1", 18);
console.log(child1.getName()); // Child1
console.log(child1.colors); // ["red", "blue", "green"]

2. 优点

  • ✅ 避免引用属性共享问题
  • ✅ 支持传参
  • ✅ 方法可以复用
  • ✅ 避免了 new Parent() 造成的二次调用

六、ES6 class 继承(最现代化的方式)

1. 实现方式

ES6 引入 class 语法,使继承更加直观:

class Parent {
  constructor(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
  }

  getName() {
    return this.name;
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name); // 继承父类属性
    this.age = age;
  }
}

const child1 = new Child("Child1", 18);
console.log(child1.getName()); // Child1
console.log(child1.colors); // ["red", "blue", "green"]

2. 优点

  • ✅ 语法简洁,易读易写
  • ✅ 继承逻辑清晰
  • ✅ super() 关键字提供更清晰的继承机制

七、总结

继承方式主要特点优点缺点
原型链继承让子类 prototype 指向父类实例方法共享共享引用属性
构造函数继承使用 call 调用父类解决共享问题,可传参方法无法复用
组合继承构造函数 + 原型链解决共享问题调用两次父类构造函数
寄生组合继承最优 ES5 方案解决所有问题代码略复杂
ES6 class 继承最现代化方案语法简洁,推荐使用仅限 ES6+

在现代 JavaScript 开发中,建议 优先使用 ES6 class 继承,但在需要兼容旧浏览器时,可以使用 寄生组合继承

以上就是JavaScript继承的实现方式详解的详细内容,更多关于JavaScript继承方式的资料请关注脚本之家其它相关文章!

相关文章

  • 一文教会你微信小程序如何实现登录

    一文教会你微信小程序如何实现登录

    微信小程序页面画好后,需要开始做一系列和用户的交互功能了,首先就是登录,这篇文章主要给大家介绍了关于微信小程序如何实现登录的相关资料,需要的朋友可以参考下
    2022-07-07
  • JS使用canvas中的measureText方法测量字体宽度示例

    JS使用canvas中的measureText方法测量字体宽度示例

    这篇文章主要介绍了JS使用canvas中的measureText方法测量字体宽度,结合实例形式分析了canvas的measureText方法相关使用技巧,需要的朋友可以参考下
    2019-02-02
  • JS异步任务的并行、串行及二者结合用法

    JS异步任务的并行、串行及二者结合用法

    让多个异步任务按照我们的想法执行,是开发中常见的需求,今天我们就来捋一下,如何让多个异步任务并行,串行,以及并行串行相结合,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • Javascript aop(面向切面编程)之around(环绕)分析

    Javascript aop(面向切面编程)之around(环绕)分析

    这篇文章主要介绍了Javascript aop(面向切面编程)之around(环绕) ,需要的朋友可以参考下
    2015-05-05
  • JS引用传递与值传递的区别与用法分析

    JS引用传递与值传递的区别与用法分析

    这篇文章主要介绍了JS引用传递与值传递的区别与用法,结合实例形式较为详细的对比分析了javascript引用传递与值传递的原理、区别、使用方法及相关操作注意事项,需要的朋友可以参考下
    2018-06-06
  • javascript forEach通用循环遍历方法

    javascript forEach通用循环遍历方法

    循环遍历一个元素是开发中最常见的需求之一,那么让我们来看一个由框架BASE2和Jquery的结合版本吧.
    2010-10-10
  • 解决Js先触发失去焦点事件再执行点击事件的问题

    解决Js先触发失去焦点事件再执行点击事件的问题

    今天小编就为大家分享一篇解决Js先触发失去焦点事件再执行点击事件的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • Webpack5正式发布,有哪些新特性

    Webpack5正式发布,有哪些新特性

    这篇文章主要介绍了Webpack5正式发布,有哪些新特性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • JS模拟实现ECMAScript5新增的数组方法

    JS模拟实现ECMAScript5新增的数组方法

    ECMAScript5 新增了十个数组方法,这些方法只有在ie9及以上浏览器中可以被使用,下面是对于这些方法的模拟实现简单介绍下,需要的朋友参考下
    2017-03-03
  • js 实现div拖拽拉伸完整示例

    js 实现div拖拽拉伸完整示例

    这篇文章主要为大家介绍了js 实现div拖拽拉伸完整示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10

最新评论