JS的六种继承方式

news2024/12/24 21:22:52

继承

什么是继承?

JS里的继承就是子类继承父类的属性和方法

目的可以让子类的实例能够使用父类的属性和方法

抽象的表达就是:一个人有车,有房,那么他的儿子也可以去使用他的车子,住他的房子。

方法一:原型链继承

话不多说,先上一个例子:

function SuperType(){this.property = true
}

function Type(){this.typeproperty = false
}

var instance = new Type()

console.log(instance.property) 

这里我们有两个构造函数,分别是:SuperType 和 Type

这里我们对 console.log(instance.property) 进行了打印,那么结果是显而易见的

构造函数 Type 的实例对象 instance 身上根本就不存在 property 属性,这个打印自然是

—— undefined

那么如果我想要在 Type 的实例对象 instance 身上拿到 SuperType 身上的属性该怎么去做呢?

很简单,这里我们就要用到我们的第一个方法——原型链继承

我们只需要让 SuperType 的实例对象变成 Type 构造函数的原型;

即改成如下:

function SuperType(){this.property = true
}

Type.prototype = new SuperType()

function Type(){this.typeproperty = false
}

var instance = new Type()

console.log(instance.property) 

那么我们打印出来的结果就是:

这说明我们是可以拿到构造函数 SuperType 身上的 property 属性

当然,这种方法有几个的缺陷

  • 会在子类实例上共享父类所有的引用类型的实例属性
  • 不能给父类构造函数传参

那么什么叫“会在子类实例上共享父类所有的引用类型的实例属性”呢?

抽象来说,就是一个人有一套房子和30万的欠债,同时他还有一个儿子,那么他的儿子肯定是只想要继承拿一套房子,而不想继承那30万的欠债对吧(当然,这里只是举个栗子);可是如果用了原型链继承那么它就会不管三七二十一,把所有的用的到的,用不到的全部继承过来。

那么什么又叫不能给父类构造函数传参呢?

我们都知道,在 new 一个实例对象时,我们是可以朝构造函数里传参来修改一些属性值,但是什么叫不能给父类构造函数传值呢?来,我们一起看看下面代码你就懂了。

function SuperType(){this.property = true
}

Type.prototype = new SuperType()

function Type(str){this.typeproperty = str
}

var instance = new Type('我是参数')

console.log(instance) 

我们看看打印结果:

这里我们成功通过传参的方式,改变了实例对象里的初始属性值;

而我们是没有任何办法去通过传参的方式修改它的父类 SuperType 里的属性值;

这就是它的第二个缺陷——不能给父类构造函数传参

方法二:经典继承(伪造对象)

同样是这个例子

function SuperType(){this.property = true
}

function Type(){this.typeproperty = false
}

var instance = new Type()

console.log(instance.property) 

经典继承的原理是:在子类的身体里将父类的所有属性方法解构在其中,让儿子具备父亲所有的属性方法。

用笨一点的话来说,就是在子构造函数里面,用遍历把父类所有的属性方法遍历一遍拿出来,然后放到子构造函数里面,达到人为改造继承的样子;不过这里是改变 this 的指向达到这样的效果。

代码实现如下:

function SuperType(){this.color = 'red'
}

function Type(){SuperType.call(this);
}

var instance = new Type()

console.log(instance.color) 

那么结果也是显而易见的:

这里要注意一点,需要用call这个方法把 SuperType 的 this 绑定到 Type 身上,保证 this 不会出现隐式丢失。

值得一提的是,经典继承这个方法不会导致它的实例对象会共享到其它实例对象的属性,且能传参。 但是缺点还是有的,那就是:1. 方法不能复用;2. 子类继承不到父类原型上的属性;

方法三:组合继承(伪经典继承)

组合继承是一种由原型链继承及经典继承的组合起来的继承方式,既解决了原型链继承里的不能传参的弊端,又解决了经典继承里不能继承到原型链上的属性方法的弊端。

代码如下:

function SuperType(age){this.color = 'red';this.age = age;
}
SuperType.prototype.name = '阿轩';

function Type(age){SuperType.call(this,age);//绑定this
}
Type.prototype = new SuperType();//将父类实例对象绑定到子类原型上
Type.prototype.constructor = Type//弥补因为重写原型而没有构造器属性的缺陷
var instance = new Type(18);

console.log(instance.color)
console.log(instance.name)
console.log(instance.age) 

喏,运行结果如下:

这种组合式继承方式解决了原型链继承还有经典继承的弊端,可以说是比较全方面一点的继承方式,但是它也是有一个缺点,那就是无论在什么情况下,都需要重复调用两次父类构造函数,算是性能方面的缺陷吧。

方法四:原型式继承

这是一种跟原型链继承相似的继承方式,通过名字也是能看出来它们是有关联的。

讲到原型式继承,那么我们就要讲到一个创建对象的方法了,它就是: Object.create() 方法。

可能大家都知道 Object.create() 方法可以创建对象,可你们知道吗,它还可以让创建出来的对象继承到其它对象的属性方法。

那么,让我们看到如下代码吧:

var person = {name:'阿轩',age:'20',
}

var obj = Object.create(person);
console.log(obj); 

如果只是拿到 Node环境 执行的话,我们只能看到一个空对象,这里,我们拿到浏览器环境下去执行给大家看:

大家可以看到,它确实只是一个空对象,但是在它的原型上,却继承到 person 对象的所有属性,这就是原型式继承;

而 Object.create() 方法的原理则是如下代码演示:

function object(obj){function F(){}//创建一个构造函数F.prototype = obj;//将传进来的参数对象重写构造函数的原型return new F(); //返回出去一个F构造函数的实例对象
}
var person = {name:'阿轩',age:'20',
}
var obj = Object(person); 

它的实现原理很简单,其实也就是原型链继承差不多。缺点:引用类型的属性始终会被继承所共享。 缺点“引用类型的属性始终会被继承所共享”解释:像这个地方有一个 person 作为引用类型传递进去,如果 person 里还有嵌套对象如下:

function object(obj){function F(){}//创建一个构造函数F.prototype = obj;//将传进来的参数对象重写构造函数的原型return new F(); //返回出去一个F构造函数的实例对象
}
var person = {name:'阿轩',age:'20',like:{sport:'singing'}
}
var obj = object(person);
obj.like.sport = 'runing'
var obj1 = object(person);
console.log(obj1) 

那么在这里的Obj1原型上的 sport 属性也会因为 obj 更改了 person 里面的引用类型里的 sport 属性的更改而更改,因为整个 person 都是一个引用地址,相当于儿子可以改动父亲的基因了,属于一个很大的弊端了。

方法五:寄生式继承

寄生式继承是原型式继承的功能添加版,它给原型式继承方法添加了一个功能,就是可以往对象上额外添加属性方法;

但是说到底,其实只是在 object.create() 方法身上嵌套一层函数,然后在函数里添加方法罢了。

如代码:

function js(obj){let clone = Object.create(obj);clone.say = () =>{console.log('新增添的可调用函数')}
}
var person = {name:'阿轩',age:'20',like:{sport:'singing'}
}
var obj2 = js(person); 

所以这种寄生式继承只是原型式继承的功能补充,而不是原型式继承的缺陷弥补,它仍然具有原型式继承的缺陷:引用类型的属性始终会被继承所共享。

寄生组合式继承

寄生组合式继承是一种原型式继承和经典继承的组合继承方式,它变相的解决了原型式继承的弊端。

function SuperType(age){this.color = 'red';this.age = age;
}
SuperType.prototype.name = '阿轩';

function Type(age){SuperType.call(this,age);//绑定this
}
Type.prototype = Object.assign(Type.prototype,SuperType.prototype) 
Type.prototype.constructor = Type
var instance = new Type(18);

console.log(instance.color)
console.log(instance.name)
console.log(instance.age) 

这里用 Object.assign 去代替了 Object.create ,把父类的原型融入到子类的原型上,且以对象的形式放到 Type 的原型上,且这些原型一般是不会发生改变的,故即引用类型的属性始终会被继承所共享也是没有关系的,变相的解决了这些问题。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

Seata流程源码梳理上篇-TM、RM处理

这一篇我们主要来分析下Seata的AT模式的流程处理。一、流程案例 1、案例源码 ​ 我们本地流程梳理用的是基于spring-cloud框架,注册中心是eurak,服务间调用的是feign,源码下载的是官网的(当然你如果对dubbo更熟悉,也…

CSDN博客之星年度评选活动 - 2022

文章目录一、2022年CSDN博客之星评选活动报名二、2022年CSDN博客之星评选活动流程线上评分流程争议(官方最后证实公布后会更新)三、2022年CSDN博客之星评选规则四、2022年CSDN博客之星评分规则五、2022年CSDN博客之星活动奖品「博客之星」奖品「博客新星…

CInternetSession OpenURL没反应,不能捕获异常

本文迁移自本人网易博客,写于2013年10月22日CString sFileName;CInternetSession iSession;BOOL bRet FALSE;CStdioFile* pFileDown NULL;try{pFileDown iSession.OpenURL(szURL, 1, INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_DONT_CACHE);}catch(...){CStri…

2023/1/8 Vue学习笔记-4-脚手架及相关属性配置

1 创建脚手架 (1)CLI就是 command line interface 的缩写。Vue CLI官网:Vue CLI (2)安装过程: (PS: 提前安装过node.js了,没有安装的可以打开这个:Download …

什么是布隆过滤器?——超详细解析【建议收藏】

目录 1、什么是布隆过滤器? 2、实现原理 2.1、回顾哈希函数 2.1.1、哈希函数概念 2.1.2、散列函数的基本特性: 2.2、布隆过滤器数据结构 3、特点 3.1、支持删除吗? 3.2、优点 3.3、缺点 3.4、误判率 4、如何选择哈希函数个数和布…

3 机器学习之聚类

学习笔记自,慕课网 《Python3 入门人工智能》 https://coding.imooc.com/lesson/418.html#mid32716 分类问题 1. 无监督学习 机器学习的一种方法,没有给定事先标记过的训练示例,自动对输入的数据进行分类或分群 优点: 1&#xf…

今年十八,喜欢CTF-杂项

目录 前言 菜狗杯杂项签到 我吐了你随意 损坏的压缩包 misc4 misc5 前言 🍀作者简介:被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 🍁个人主页:被吉师散养的职业混子 🫒每日emo&am…

Rad Studio 11.2 安装 QuickBurro 7.21 中间件组件教程

背景 QuickBurro 官方网址:http://www.quickburro.org/ 系统环境:Rad Studio 11.2 安装其他的组件操作和这个一样的,同样可以参考 开始配置 先打开 Rad Studio 11,依次点击 File–Open Project… 然后找到你解压的 qbcn 目录下的…

React 环境搭建以及创建项目工程(二)

创建工程 首先创建一个工程 npx create-react-app weibo cd移动到当前创建的文件下 cd weibo 安装 React 路由 npm install react-router react-router-dom5.2.0 --save 安装 npm install 安依赖包 npm install antd --save npm install axios --save 安装less和less-…

PyCharm安装步骤

以64位的Windows10系统为例: 下载链接:Thank you for downloading PyCharm! 下载并打开安装包 在 Installation Options(安装选项)页面按下图所示勾选相应内容: 等待电脑自动安装完成 在PyCharm里编写程序 第1步&a…

【python】天平最少砝码设计

题目 有一架天平,砝码的种类和个数要你来设计。给定一个整数n,则待称重的物品的重量可能是 [1,n] 之间的整数,砝码可以放在左盘也可以放在右盘,要能称出所有 [1,n] 重量的物品,请问如何设计砝码的种类和个数&#xff…

Unreal UFUNCTION函数宏标记

BlueprintCallable,使C中的函数在蓝图中能被调用,新建C类CustomActor继承AActor,并分别声明public、protected、private方法:拖拽一个CustomActor到Map中,打开关卡蓝图,可以到无法在蓝图中调出C中的方法:我们为这三个方法添加BlueprintCallable标记:然后在蓝图中调用:可以发现,…

驱动程序开发:多点电容触摸屏

驱动程序开发:多点电容触摸屏一、编写驱动前的知识准备1、CST340触摸屏芯片寄存器2、CST340触摸屏的硬件原理图3、电容触摸屏驱动是由几种linux驱动框架组成的4、linux多点电容触摸的(Multi-touch,简称 MT)协议二、驱动程序的编写1、修改设备树2、驱动程…

Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】

Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】🍎一. Spring AOP🍒1.1 什么是Spring AOP🍒1.2 Spring AOP的作用🍒1.3 AOP的组成🍉1.3.1 切面(Aspect)🍉1.3.2 连接点…

大数据NiFi(十一):NiFi入门案例一

文章目录 NiFi入门案例一 一、配置“GetFile”处理器

Elastic-Job分布式任务调度

一.什么是任务调度 **任务调度:**是指系统为了自动完成特点任务,在约定的特定时刻去执行任务的过程。有了任务调度就不需要人力去实现,系统可以在某个时间自动执行任务。 二,任务调度的实现方式: 1.**多线程方式实现…

【博客579】netfilter network flow 和 routing decision的网络流处理交互关系

netfilter网络流转(network flow)与路由决策(routing decision)的网络流处理交互关系 1、场景: 我们可以通过iptables来基于netfilter机制下发我们的hook处理函数,那么我们平时iptables的四表五链与报文的…

JDBC简介

大家好,今天给大家分享jdbc 首先我们要知道什么是jdbc JDBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术 看它的架构图 或者看这个图…

flowable工作流架构分析

flowable工作流目录概述需求:设计思路实现思路分析1.复杂的状态的或者状态的维度增加的状的条件极为复杂2.工作流3.BPMN2.0协议4.协议的元素5.互斥网关包容性网关(Inclusive Gateway)参考资料和推荐阅读Survive by day and develop by night.…

车载以太网 - DoIP诊断消息处理逻辑 - 05

前面我们已经介绍了DoIP信息头部处理逻辑和路由激活处理,那根据DoIP报文的顺序,在路由激活处理完成后,接下来我们就需要发送真正的DoIP诊断信息了,那今天我们就来介绍下DoIP诊断消息的处理逻辑。 诊断消息处理逻辑 DoIP诊断报文结构: 上面表格对于DoIP诊断报文的…