JavaScript 继承百花齐放:从原型链到 ES6 类

news2025/1/23 1:04:15

 前言

 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步!

 🍅 个人主页:南木元元

在 JavaScript 中,继承是一个重要的知识点,上篇文章中我们已经了解了原型和原型链的概念,本文就来介绍一下js中实现继承的几种方式。


目录

继承

实现继承的方法

1.原型链继承

2.借用构造函数继承

3.组合继承

4.原型式继承

5.寄生式继承

6.寄生组合式继承

7.class继承

结语


继承

继承,简单来讲就是让子类能够访问到父类的属性和方法,继承的主要作用就是实现代码的重用。

在JavaScript中,主要通过原型链来实现继承。我们重温一下构造函数、原型和实例的关系:

每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个指针指向原型。

实现继承的方法

1.原型链继承

原型链继承的基本思想:让子类构造函数的原型指向父类的实例。

function Parent () {
   this.name = 'kevin';
}
Parent.prototype.getName = function () {
   console.log(this.name);
}
function Child () {}

//让子类原型指向父类实例
Child.prototype = new Parent();
var child1 = new Child();
console.log(child1.getName()) // kevin

缺点是引⽤类型的属性被所有实例共享,并且创建子类型实例时,不能向父类型传参。

2.借用构造函数继承

基本思想:在子类构造函数中调用父类构造函数,使用call将父对象的构造函数绑定在子对象上。

function Parent () {
  this.names = ['kevin', 'daisy'];
}
function Child () {
  // 调用父类构造函数
  Parent.call(this);
}

var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy"]

解决了原型链继承不能传参问题和父类原型共享问题,但是无法实现函数方法的复用,方法都在构造函数中定义,每次创建实例都会创建一遍方法,方法本质上都变成了实例自己的方法,不是公共的方法。

3.组合继承

基本思想:将原型链和借用构造函数组合起来使用。使用原型链实现对原型方法的继承,通过借用构造函数的方式来实现属性的继承。

function Parent (name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
  console.log(this.name)
}
function Child (name, age) {
  Parent.call(this, name);
  this.age = age;
}

Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('kevin', '18');
child1.colors.push('black');
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
var child2 = new Child('daisy', '20');
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

这种方式的优点:既实现了函数复用,又保证每个实例都有自己的属性。

缺点:调用了两次父类的构造函数,造成了子类的原型中多了很多不必要的属性。

4.原型式继承

基本思想:基于已有的对象来创建新的对象。

// 利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型
function createObj(o) {
   function F() {}
   F.prototype = o;
   return new F();
}
var person = {
  name: 'kevin',
  friends: ['daisy', 'kelly']
}
var person1 = createObj(person);
var person2 = createObj(person);
person1.name = 'person1';
console.log(person2.name); // kevin
person1.friends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

缺点是引⽤类型的属性被所有实例共享。

ES5中存在Object.create()的方法,能够代替上面的createObj方法。

5.寄生式继承

寄生式继承与原型式继承很接近,它的思想就是在原型式继承的基础上以某种方式增强对象,然后返回这个对象。

function createObj (o) {
   let clone = Object.create(o);
   clone.sayName = function () {
       console.log("hi");
  }
   return clone;
}

6.寄生组合式继承

组合继承的缺点就是调用了2次父构造方法。寄生组合式继承就是改造组合式继承,使用父类的原型的副本来作为子类的原型,这样就只调用一次父构造函数,避免了创建不必要的属性。

function Parent (name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
  console.log(this.name)
}
function Child (name, age) {
  Parent.call(this, name);
  this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;//把子类的构造指向子类本身
var child1 = new Child('kevin', '18');
console.log(child1.colors);//[ 'red', 'blue', 'green' ]
console.log(child1.getName());//kevin

7.class继承

在 ES6 中,可以使用 class 去实现继承。使用 extends 表明继承自哪个父类,并且在子类构造函数中必须调用 super 。

class Parent {
 constructor(name) {
   this.name = name;
}
 getName() {
   console.log(this.name);
}
}
class Child extends Parent {
 constructor(name, age) {
   super(name);
   //使用this之前必须先调用super()
   this.age = age;
}
}
// 测试
let child = new Child("kevin", 18);
console.log(child.name); // kevin
console.log(child.age); // 18
child.getName(); // kevin

注意:在 JS 中并不存在类, class 只是语法糖,本质还是函数。

class Person {}
Person instanceof Function // true

class实现的继承本质上是寄生组合式继承。下面是使用babel将ES6代码编译成ES5后的代码:

function _possibleConstructorReturn(self, call) {
    // ...
    return call && (typeof call === 'object' || typeof call === 'function') ? call : self;
}

function _inherits(subClass, superClass) {
    // ...
    //看到没有
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}


var Parent = function Parent() {
    // 验证是否是 Parent 构造出来的 this
    _classCallCheck(this, Parent);
};

var Child = (function (_Parent) {
    _inherits(Child, _Parent);

    function Child() {
        _classCallCheck(this, Child);

        return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).apply(this, arguments));
    }

    return Child;
}(Parent));

核心是_inherits函数,可以看到它采用的依然也是寄生组合继承方式。不过这里加了一个Object.setPrototypeOf(subClass, superClass),这是用来干啥的呢?

答案是用来继承父类的静态方法。这也是原来的继承方式疏忽掉的地方。

  • ES5 继承和 ES6 继承的区别

ES5 的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上 Parent.call(this) 

ES6 的继承不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1978213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java】Java Swing 图书管借阅管理系统(源码+论文)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

python rsa如何安装

Python中的一些模块是用一个包管理器来发布的,RSA模块就是,所以首先需要安装setup tools工具。 1、下载文件:ez_setup.py 2、安装: sudo python ez_setup.py 3、下载RSA安装包:rsa-3.1.1-py2.7.egg 4、安装RSA&…

牛客JS题(二十一)数组扁平化

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; 递归flat字符串操作正则表达式替换 题干&#xff1a; 我的答案 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /></head><body><script&…

Dubbo源码深度解析(中)

接着《Dubbo源码深度解析(上)》继续讲&#xff0c;上篇博客主要讲Dubbo提供的三个注解的作用&#xff0c;即&#xff1a;EnableDubbo、DubboComponentScan、EnableDubboConfig。其中后两个注解是在EnableDubbo上的&#xff0c;因此在启动类上加上EnableDubbo注解&#xff0c;等…

数据分析模型:洞察数据背后的奥秘

数据分析模型&#xff1a;洞察数据背后的奥秘 事件分析模型通过对用户行为事件的深入剖析&#xff0c;能够了解用户在产品上的具体行为&#xff0c;为产品优化和营销策略提供了有力依据。漏斗分析模型则专注于用户转化流程&#xff0c;帮助找出业务流程中的薄弱环节&#xff0c…

[Meachines] [Easy] Sense PFSense防火墙RCE

信息收集 IP AddressOpening Ports10.10.10.60TCP:80,443 $ nmap -p- 10.10.10.60 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 80/tcp open http lighttpd 1.4.35 |_http-title: Did not follow redirect to https://10.10.10.60/ |_http-server-header…

zlm-openRtpServer使用

http://127.0.0.1/index/api/openRtpServer?port50253&tcp_mode1&stream_idtest123&secretLSAjqhPDsC0IcL27hI6U8heTxgnTlZlW使用getRtpInfo查看这个流的情况&#xff0c;注意只有这个端口在接受流的时候&#xff0c;才会返回数据 http://127.0.0.1/index/api/ge…

【文献阅读】TAM: Topology-Aware Margin Loss for Class-Imbalanced Node Classification

Abstract 在类别不平衡的图数据中学习无偏的节点表示是一项具有挑战性的任务&#xff0c;因为相邻节点之间存在相互作用。现有研究的共同点在于&#xff0c;它们根据少数类节点的总体数量“作为一个整体”进行补偿&#xff08;忽略了图中的节点连接&#xff09;&#xff0c;这…

理解<共轭复数乘法,复数乘法,复数除法>

目录 复数乘法共轭复数乘法的理解复数除法 复数乘法 共轭复数乘法的理解 共轭复数乘法&#xff1a;可以理解为滤波&#xff0c;计算两序列的相关。即一个序列固定&#xff0c;另一个序列进行滑动计算该点的累积和。因为傅里叶变换的卷积定理&#xff0c;时域卷积对于频域相乘。…

web漏洞-知识点详解

先放张图&#xff01;右边漏洞比左边漏洞更重要&#xff01;右边漏洞更多&#xff01;重点讲述右边漏洞&#xff01; sql注入 危害情况&#xff1a;可以获取网站数据库中的数据&#xff0c;如果数据中有敏感信息&#xff0c;比如管理员账号密码&#xff0c;就可以登录后台 漏…

学生管理系统之更新和删除、筛选

学生管理系统之更新和删除 建立新的窗口 添加组件 进行布局 使用Widget把二个放在一块,作为一列,然后全选进行栅格布局,最后添加弹簧进行微调。 编写增加的槽函数 在主函数中调用对话框

CC++内存魔术:掌控无形资源

hello,uu们,今天呢我们来详细讲解C&C的内存管理,好啦,废话不多讲,开干 1:C/C内存分布 2:C语言中动态内存管理方式:malloc/calloc/realloc/free 3:C内存管理方式 3.1:new/delete操作内置类型 3.1.1:代码1 3.1.2:代码2 3.2:new和delete操作自定义类型 3.2.1:C语言创建…

初识增强现实(AR)

初识增强现实&#xff08;AR&#xff09; 笔记来源&#xff1a; 1.2023年中国增强现实&#xff08;AR&#xff09;行业研究报告 2.wiki/Augmented reality 3.In-Depth Review of Augmented Reality: Tracking Technologies, Development Tools, AR Displays, Collaborative AR…

js第二天

比较运算符 ==左右两边值是否相等 ===左右两边值和类型是否全相等 !==左右两边是否类型和值全不相等 undefin === null NaN === NaN(错误,NaN不等于任何值) =单等是赋值 ==双等是判断 ===三等是全等,开发中判断是否相等,一般用全等。 console.log 先比较a和a,相…

电脑添加虚拟网卡与ensp互联,互访

一、按照过程 1、打开设备管理器 2、点击网络适配器&#xff0c;点击左上角操作&#xff0c;点击“添加过时硬件” 3、下一页 4、选择“安装我手动从列表选择的硬件”&#xff0c;下一页 5、下拉&#xff0c;选择“网络适配器”&#xff0c;下一页 6、厂商选择“Microsoft”&…

基于MFC对话框吸管实验

1.新建项目 2.将bmp图像放入res文件下 3.导入bmp文件到bitmap 4.在dlg中添加picture控件&#xff0c;修改控件属性&#xff08;Type Image属性&#xff09;&#xff0c;把bitmap资源添加到控件中 5.重写鼠标单击鼠标中键响应事件 6.主要源代码 void CMFC吸管Dlg::OnMButtonDow…

使用Springboot + netty 打造聊天服务之Nacos集群问题记录

目录 1、前言1.1、方法一1.2、方法二 2、方案二实战2.1、在netty服务里加上ws连接、中断事件2.2、在netty服务里加上消息服务 4、总结 使用Springboot netty 打造聊天服务系列文章 第一章 初始搭建工程 第二章 Nacos集群问题记录 1、前言 在使用Springboot Nacos Netty(Web…

SAPUI5基础知识23 - 模型的种类(小结)

1. 背景 在前序的学习中&#xff0c;我们学习了SAPUI5的MVC架构中的各个知识点&#xff0c;包括视图的设计&#xff0c;控制器的设计&#xff0c;以及模型的使用。 在企业级应用程序中&#xff0c;对于数据的处理的需求是很大的&#xff0c;在学习更复杂的数据绑定方式之前&a…

Pr2024苹果(mac)版剪辑软件安装下载(附下载链接)

Adobe Premiere Pro 2024&#xff08;简称PR 2024&#xff09;是一款由Adobe公司开发的专业视频编辑软件&#xff0c;被广泛应用于电影、电视、广告和社交媒体视频的制作。以下是对PR 2024的详细简介&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rN-3kB3KQgn0JswDa…

《学会 SpringMVC 系列 · 剖析初始化》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…