js常见的七种继承及实现
在 JavaScript 中,常见的继承方式有以下七种:
大厂面试题分享 面试题库
前后端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
1. 原型链继承
原型链继承是 JavaScript 中一种基于原型的继承方式,它通过将一个构造函数的实例作为另一个构造函数的原型,从而实现继承。具体来说,就是在子类的构造函数中通过 Child.prototype = new Parent() 的方式来继承父类的属性和方法。
以下是一个实现原型链继承的示例代码:
// 定义父类构造函数functionParent(name) {this.name = name;
}// 父类原型上的方法Parent.prototype.sayName = function() {console.log('My name is ' + this.name);
}// 定义子类构造函数functionChild(name, age) {this.age = age;
}// 将子类的原型设置为父类的实例Child.prototype = newParent();// 子类原型上的方法Child.prototype.sayAge = function() {console.log('I am ' + this.age + ' years old');
}// 创建子类实例var child = newChild('Tom', 10);// 调用子类实例的方法
child.sayName(); // My name is Tom
child.sayAge(); // I am 10 years old复制代码
在上面的示例代码中,我们首先定义了一个父类构造函数 Parent,并在其原型上定义了一个方法 sayName。然后我们定义了一个子类构造函数 Child,并通过将子类的原型设置为父类的实例来实现继承。最后我们创建了一个子类实例 child,并调用其方法来验证继承是否成功。
优点:
简单易懂:原型链继承是一种简单的继承方式,易于理解和实现。
父类方法更新会自动同步到子类实例:由于子类实例的原型指向父类实例,所以父类的方法更新会自动同步到子类实例中。
可以重用父类方法:由于子类实例可以访问父类的原型,因此可以重用父类的方法,从而减少代码量。
缺点:
所有子类实例共享原型对象:由于所有子类实例的原型都指向同一个对象,因此一个实例对原型对象的修改会影响到其他实例。
无法向父类构造函数传递参数:原型链继承无法向父类构造函数传递参数,因此子类实例无法向父类构造函数传递参数,也无法对父类实例进行初始化。
无法实现多继承:由于JavaScript中一个对象只能有一个原型对象,因此原型链继承无法实现多继承。
2. 借用构造函数继承
JavaScript中的借用构造函数继承是一种通过调用父类构造函数来实现继承的方式。这种继承方式有以下特点:
子类实例拥有了父类构造函数中定义的属性和方法。
子类实例与父类实例之间不存在原型链的关系,因此可以避免共享原型对象带来的问题。
子类无法重用父类原型对象上的方法。
以下是一个借用构造函数继承的示例代码:
functionAnimal(name) {this.name = name;
}Animal.prototype.sayName = function() {console.log('My name is ' + this.name);
}functionDog(name, age) {Animal.call(this, name); // 借用Animal构造函数,并将this指向Dog实例this.age = age;
}let dog1 = newDog('旺财', 2);
let dog2 = newDog('小白', 1);console.log(dog1.name); // '旺财'console.log(dog2.age); // 1
dog1.sayName(); // TypeError: dog1.sayName is not a function复制代码
在上面的代码中,Dog类通过调用Animal构造函数来实现继承,从而拥有了Animal类中定义的属性和方法。由于子类实例与父类实例之间不存在原型链的关系,因此修改一个实例的属性不会影响到其他实例。
但是需要注意的是,由于子类实例无法访问父类原型对象上的方法,因此在上面的代码中,dog1实例调用sayName()方法会报错。如果需要在子类中重用父类原型对象上的方法,可以考虑使用组合继承或寄生组合式继承。
优点:
可以向父类构造函数传递参数:借用构造函数继承可以向父类构造函数传递参数,从而可以对父类实例进行初始化。
避免了原型对象共享的问题:由于借用构造函数继承创建了一个新的对象,因此避免了原型对象共享的问题。
可以实现多继承:由于JavaScript中可以在一个构造函数中调用多个构造函数,因此可以通过借用构造函数继承来实现多继承。
缺点:
无法重用父类方法:由于借用构造函数继承创建了一个新的对象,因此无法重用父类的方法。
父类方法更新不会自动同步到子类实例:由于借用构造函数继承创建了一个新的对象,因此父类的方法更新不会自动同步到子类实例中。
无法访问父类原型上的属性和方法:由于借用构造函数继承只继承了父类的实例属性和方法,因此无法访问父类原型上的属性和方法。如果需要访问父类原型上的属性和方法,仍然需要通过将子类的原型指向父类的实例来实现。
3. 组合继承
JavaScript中的组合继承是一种结合借用构造函数和原型链继承的方式,它的核心思想是使用借用构造函数继承实例属性和方法,使用原型链继承共享属性和方法。
以下是一个组合继承的示例代码:
functionAnimal(name) {this.name = name;
}Animal.prototype.sayName = function() {console.log('My name is ' + this.name);
}functionDog(name, age) {Animal.call(this, name); // 借用Animal构造函数,并将this指向Dog实例this.age = age;
}Dog.prototype = newAnimal(); // 原型链继承Animal类的属性和方法Dog.prototype.constructor = Dog; // 修复构造函数指向let dog1 = newDog('旺财', 2);
let dog2 = newDog('小白', 1);console.log(dog1.name); // '旺财'console.log(dog2.age); // 1
dog1.sayName(); // 'My name is 旺财'复制代码
在上面的代码中,Dog类通过借用Animal构造函数继承实例属性和方法,通过原型链继承Animal类的属性和方法。由于子类实例与父类实例之间不存在原型链的关系,因此修改一个实例的属性不会影响到其他实例。同时,子类实例可以重用父类原型对象上的方法。
需要注意的是,由于在上面的代码中通过Dog.prototype = new Animal()创建了一个新的Animal实例,因此在创建Dog类时会调用两次Animal构造函数,造成了性能上的浪费。可以使用寄生组合式继承来解决这个问题。
具体来说,组合继承通过将父类的构造函数借用到子类中,从而实现了父类属性的继承,同时通过将子类的原型设置为一个新的父类实例,从而实现了父类方法的继承。这种继承方式具有以下优缺点:
优点:
父类的构造函数可以传递参数,并且不会影响到其他实例。
子类实例可以访问父类原型对象上的方法,可以重用父类的方法。
可以实现多继承。
实现简单、易于理解。
缺点:
子类实例会同时拥有自己的属性和方法,以及父类的属性和方法,可能导致内存浪费和属性名冲突的问题。
在创建子类实例时,父类构造函数会被调用两次,可能会影响性能。
4. 原型式继承
JavaScript中的原型式继承是一种基于已有对象创建新对象的继承方式,它利用了对象的动态特性,通过封装一个函数来实现继承。该函数接收一个用作新对象原型的对象作为参数,并返回一个新对象,从而实现了继承。该方式与借用构造函数继承类似,但它并不涉及到构造函数和实例的概念。原型式继承具有以下特点:
基于已有对象创建新对象。
可以使用Object.create()方法实现。
可以将一个对象作为另一个对象的原型对象。
可以使用原型对象的属性和方法,但不会影响到原型对象本身。
下面是一个使用原型式继承的示例代码:
let animal = {type: 'animal',sayType: function() {console.log('I am a ' + this.type);}
};let dog = Object.create(animal); // 使用animal对象作为dog对象的原型
dog.type = 'dog';dog.sayType(); // 'I am a dog'复制代码
在上面的代码中,animal对象拥有一个type属性和一个sayType方法,dog对象通过使用animal对象作为原型对象来实现了继承。因此,dog对象可以使用原型对象的属性和方法,但并不会影响到原型对象本身。此外,通过给dog对象添加一个type属性,也可以覆盖原型对象的type属性,实现对父对象属性的重写。原型式继承的优点在于可以方便地实现对象的复用,但也容易导致对象之间的耦合,不易于维护。
具体来说,它通过创建一个空对象,并将其原型设置为一个已有对象,然后向这个空对象中添加属性和方法来实现继承。原型式继承具有以下优缺点:
优点:
简单、易于理解和实现。
可以基于一个对象创建多个对象,实现对象复用。
缺点:
父对象的引用属性会被所有子对象共享,因此子对象的修改会影响到其他子对象。
子对象无法像传统的类继承一样判断自己是否是父对象的实例。
无法实现多继承。
5. 寄生式继承
JavaScript中的寄生式继承是一种基于已有对象创建新对象的继承方式,类似于原型式继承。它的主要区别是,在新创建的对象上增加一个方法,而这个方法的作用是以某种方式增强对象,然后返回这个对象。这种继承方式得名于“寄生”,因为增强对象的方法通常是基于已有的对象进行“寄生”而得名。
寄生式继承的优点是可以封装继承过程,并且可以向对象中添加一些额外的属性和方法。但是和原型式继承一样,也存在父对象的引用属性被所有子对象共享、无法判断实例是否是父对象的实例等问题。
以下是一个使用寄生式继承的示例代码:
functioncreateAnimal(type) {let animal = {type: type,sayType: function() {console.log('I am a ' + this.type);}};// 基于animal对象进行寄生增强let dog = Object.create(animal);dog.bark = function() {console.log('woof woof');};return dog;
}let myDog = createAnimal('canine');
myDog.sayType(); // 'I am a canine'
myDog.bark(); // 'woof woof'复制代码
在上面的代码中,我们定义了一个名为createAnimal的函数,用于创建一个继承自animal对象的新对象。我们在这个新对象上增加了一个bark方法,用于让对象发出叫声。最后,我们返回这个新对象,并将它赋值给myDog变量。通过这样的方式,我们成功地实现了寄生式继承。
具体来说,它在原型式继承的基础上增加了一个包装函数,该函数用于封装继承过程中的一些增强行为。寄生式继承具有以下优缺点:
优点:
简单、易于理解和实现。
可以基于一个对象创建多个对象,实现对象复用。
可以在不修改原对象的情况下,对继承过程进行一些增强,例如添加新的属性和方法。
缺点:
父对象的引用属性会被所有子对象共享,因此子对象的修改会影响到其他子对象。
子对象无法像传统的类继承一样判断自己是否是父对象的实例。
增强行为可能会带来一定的性能开销。
可能会导致代码的可读性降低。
6. 寄生式组合继承
JavaScript中的寄生式组合继承是一种结合了组合继承和寄生式继承的继承方式。具体来说,它在组合继承的基础上,通过寄生式继承来解决组合继承中重复调用父构造函数的问题。
下面是一个使用寄生式组合继承的示例代码:
functionAnimal(name) {this.name = name;this.type = 'mammal';
}Animal.prototype.sayName = function() {console.log('My name is ' + this.name);
};functionDog(name, breed) {Animal.call(this, name);this.breed = breed;
}// 使用寄生式继承继承Animal.prototypeDog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;Dog.prototype.sayBreed = function() {console.log('I am a ' + this.breed);
};let myDog = newDog('Max', 'Golden Retriever');
myDog.sayName(); // 'My name is Max'
myDog.sayBreed(); // 'I am a Golden Retriever'复制代码
在上面的代码中,我们定义了Animal和Dog两个构造函数,其中Animal构造函数定义了一个name属性和一个sayName()方法,Dog构造函数在Animal的基础上添加了一个breed属性和一个sayBreed()方法。为了实现寄生式组合继承,我们使用Object.create()方法基于Animal.prototype创建了一个新的对象,并将其赋值给Dog.prototype,从而使得Dog.prototype的原型链指向了Animal.prototype。同时,我们还将Dog.prototype的constructor属性设置为Dog,以保证继承链的完整性。最后,我们通过调用Animal构造函数并将this指向Dog对象,实现了对Animal属性的继承。通过这种方式,我们既避免了组合继承中重复调用父构造函数的问题,又保留了寄生式继承的灵活性,实现了一个高效而且灵活的继承方式。
优点:
实现了属性和方法的完整继承。
避免了组合继承中重复调用父类构造函数的问题,提高了性能。
可以在不修改原对象的情况下,对继承过程进行一些增强,例如添加新的属性和方法。
缺点:
增加了一层包装函数,可能会带来一定的性能开销。
可能会导致代码的可读性降低。
7. class继承
在ES6及以上的版本中,JavaScript引入了class关键字,用于定义类,从而实现面向对象编程。class继承是一种通过类来实现继承的方式,它使用extends关键字来指定父类,并通过super关键字来调用父类的构造函数和方法。
以下是一个使用class继承的示例代码:
classAnimal {constructor(type) {this.type = type;}sayType() {console.log('I am a ' + this.type);}
}classDogextendsAnimal {constructor(type, name) {super(type);this.name = name;}sayName() {console.log('My name is ' + this.name);}
}let dog = newDog('canine', 'Fido'); // 创建一个新的Dog对象dog.sayType(); // 'I am a canine'
dog.sayName(); // 'My name is Fido'复制代码
在上面的代码中,我们首先定义了一个Animal类,它包含一个构造函数和一个sayType()方法。然后我们通过extends关键字来指定Dog类的父类为Animal,并在Dog类的构造函数中通过super关键字来调用Animal构造函数,并实现了sayName()方法。最后,我们创建一个新的Dog对象,并调用它的方法来测试继承是否成功。
优点:
代码可读性高,更易于理解和维护。
语法简洁,可以更快地编写代码。
可以使用现代JavaScript特性,如箭头函数、解构赋值等。
缺点:
与ES5及以下版本的JavaScript不兼容。
需要编译才能运行在低版本浏览器中。
某些开发者可能认为使用类和继承违背了JavaScript的本质。
总体来说,class继承是一种非常方便的继承方式,特别是在面向对象编程中,能够大大简化代码的编写和维护。但在一些特定情况下,其他继承方式可能更为适合。
大厂面试题分享 面试题库
前后端面试题库 (面试必备) 推荐:★★★★★
地址:前端面试题库
相关文章:
js常见的七种继承及实现
在 JavaScript 中,常见的继承方式有以下七种:大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库1. 原型链继承原型链继承是 JavaScript 中一种基于原型的继承方式&#…...

案例分析之——理由Mybatis动态SQL实现复用
无复用思想的做法: 在没有复用思想的时候,就只顾着实现功能。比如开发过程中涉及到两个表的更新功能,每需要更新一处,就写一个接口,结果出现了写了11个接口的情况。 这样虽然功能实现了,可是可能自…...

MCM 箱模型建模方法及大气 O3 来源解析实用干货
OBM 箱模型可用于模拟光化学污染的发生、演变过程,研究臭氧的生成机制和进行敏感性分析,探讨前体物的排放对光化学污染的影响。箱模型通常由化学机理、物理过程、初始条件、输入和输出模块构成,化学机理是其核心部分。MCM (Master Chemical M…...
【独家】华为OD机试 - 最长连续交替方波信号(C 语言解题)
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...

代码随想录算法训练营第二十一天打卡 | 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先
打卡第21天,继续二叉树,前几天终于补完了,感觉难度上来了。 今日任务 530.二叉搜索树的最小绝对差501.二叉搜索树中的众数 二叉树的最近公共祖先 530.二叉搜索树的最小绝对差 给你一个二叉搜索树的根节点 root ,返回 树中任意两不…...

免费下载丨一看即会,Serverless 技术进阶必读百宝书
过去一年,全球正在加速推进云计算的 Serverless 化进程。Serverless 架构已经逐渐从“被接受”走向了“被学习”和“被应用”。云的产品体系正在 Serverless 化,从计算、存储、数据库到中间件,越来越多的云产品采用了 Serverless 模式。服务器…...
SQL语句的加锁方式 - Mysql 锁机制
SQL语句的加锁方式 - Mysql锁机制 SELECT ... FROM SELECT ... FOR UPDATE / SELECT ... FOR SHARED MODE SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE UPDATE ... WHERE ... DELETE FROM ... WHERE ... INSERT INSERT ... ON DUPLICATE KEY UPDATE REPLACE Mysql锁机…...

C#开发的OpenRA的游戏主界面怎么样创建4
继续游戏主界面创建的主题, 前面已经说到怎么样找到mainmenu.yaml来显示主界面,也说了怎么样找到各个子控件类。 现在就来仔细分析一下,主界面每一部分的功能。 比如下面这个区域的界面是怎么样创建: 要创建这一小部分的界面显示,也是需要做很多的工作。 因为在这里所有UI…...

覆盖5大主流开发平台的报表控件,它值得你一看
为什么大家现在都在使用第三方报表工具呢? 第三方报表工具是数据库存储,数据库程序通常可以存放的数据量是相当大的,可以处理非常复杂的数据结构关系,报表数据交互速度也非常快。不仅能够提高开发效率,还能实现灵活美…...
【冲刺蓝桥杯的最后30天】day4
大家好😃,我是想要慢慢变得优秀的向阳🌞同学👨💻,断更了整整一年,又开始恢复CSDN更新,从今天开始更新备战蓝桥30天系列,一共30天,如果对你有帮助或者正在备…...

spring boot actuator 动态修改日志级别
1 日志级别 Spring Boot Actuator包括在运行时查看和配置应用程序日志级别的功能。您可以查看整个列表,也可以查看单个记录器的配置,该配置由显式配置的日志级别和日志框架给出的有效日志级别组成。这些级别可以是: TRACEDEBUGINFOWARNERRORFATALOFFnu…...

兴达易控Modbus转Profinet网关连接1200Profinet转modbus接三菱A800变频器案例
下面介绍A800 变频器通过兴达易控modbus转profinet网关,使1200plc无需编程实现Profinet转modbus协议转换,把modbus变频器轻松组网 网络拓扑如下图 打开博图组态加载GSD文件,modbus转profinet网关从站接口接入到1200PLC上 配置modbus转profine…...

「SAP ABAP」OPEN SQL(四)【FROM语句】
💂作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后…...

一文吃透 SpringMVC 中的转发和重定向
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
Hbase操作命令
目录 创建表,表中有两个列族 baseinfo, schoolinfo 查看指定表全名空间中的表 查看表描述 禁用/启用 查看是否启用/禁用 删除表 注意,首先要将删除的表设置为禁用状态才可以删除,否则会报错 新增列族 删除列族 更改列族存储版本的限制 增…...
1>LINK : fatal error LNK1104: cannot open file ‘libconvtname.obj‘
我自己最后找到问题原因是: 引用的库名称没有.lib,只有libconvtname。 改成完整的libconvtname.lib即可。 以下是chatGPT的回答 The error message "fatal error LNK1104: cannot open file libconvtname.obj" usually occurs when Visual S…...

数据结构——链表OJ题目讲解(1)
作者:几冬雪来 时间:2023年3月7日 内容:数据结构链表OJ题目讲解 题目来源:力扣和牛客 目录 前言: 刷题: 1.移出链表元素: 2.链表的中间结点: 3. 链表中倒数第k个结点࿱…...
LeetCode_二分搜索_困难_154.寻找旋转排序数组中的最小值 II
目录1.题目2.思路3.代码实现(Java)1.题目 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums [0,1,4,4,5,6,7] 在变化后可能得到: 若旋转 4…...

面向对象设计模式:创建型模式之建造者模式
一、引入 Build:建造和构建具有建筑结构的大型物体 建楼:打牢地基、搭建框架、然后自下而上一层层盖起来。构建物体:通常需要先建造组成这个物体的各个部分,然后分阶段把它们组装起来 二、建造者模式 2.1 Intent 意图 Separate…...

集成学习boosting、bagging、stacking
目录 一、介绍 二、三种架构学习 (1)boosting (2)bagging (3)stacking 一、介绍: 对于单个模型来说很难拟合复杂的数,模型的抗干扰能力较低,所以我们希望可以集成多…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...

Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...