当前位置: 首页 > news >正文

关于JS继承的七种方式和理解

1.原型链继承

function Fun1() {this.name = 'parent'this.play = [1, 2, 3]
}
function Fun2() {this.type = 'child'
}Fun2.prototype = new Fun1()let s1 = new Fun2()
let s2 = new Fun2()
s1.play.push(4)
console.log(s1.play, s2.play) // [1, 2, 3, 4] [1, 2, 3, 4]

可以看到两个子类实例的属性都被影响了,这是因为通过原型链继承的子类实例的属性是共享的

原型链继承的弊端

  1. 共享引用类型属性
  2. 函数无法传递参数
  3. 原型链过长导致性能问题
  4. 难以维护和调试

2.构造函数继承

function Fun1() {this.name = 'parent'
}Fun1.prototype.getName = function () {return this.name
}function Fun2() {Fun1.call(this)this.type = 'child'
}let child1 = new Fun2()
let child2 = new Fun2()
child2.type = 'xxxx'console.log(child1, child2) // Fun2 { type: 'child', name: 'parent' } Fun2 { type: 'xxxx', name: 'parent' }console.log(child1.getName()) // child1.getName is not a function

可以看到构造函数继承确实不会共享属性了,但是构造函数继承只继承了父类的实例属性和方法,而不会继承父类原型上的方法

构造函数继承的弊端

  1. 无法复用父类原型上的方法
  2. 每个子类实例都会创建新的父类实例(每次创建子类实例时,都会调用一次父类构造函数,这会导致不必要的资源消耗,尤其是在父类构造函数中有复杂初始化逻辑或大量计算时。
  3. 无法传递参数给父类构造函数(如果父类构造函数需要参数,子类构造函数必须显式地传递这些参数,否则父类构造函数中的初始化逻辑可能无法正常工作。
  4. 难以维护和调试(构造函数继承的代码结构相对复杂,特别是在多层继承的情况下,可能会导致代码难以理解和维护。此外,调试时也更难追踪继承链中的问题。

3.组合继承(伪经典继承)

function Fun1(name) {this.name = namethis.play = [1, 2, 3]
}Fun1.prototype.getName = function () {return this.name
}function Fun2() {Fun1.call(this, 'haha')this.type = 'child'
}Fun2.prototype = new Fun1()// 修复构造函数指针,确保子类的 constructor 属性正确指向其自身的构造函数
// 如果不写这段代码,下面的 child1 和 child2 的 constructor 就会指向 Fun1
Fun2.prototype.constructor = Fun2 let child1 = new Fun2()
let child2 = new Fun2()
console.log(child1.constructor === Fun2) // true
console.log(child2.constructor === Fun1) // falsechild1.play.push(4)
console.log(child1.play, child2.play) // [1, 2, 3, 4] [1, 2, 3]console.log(child1.getName(), child2.getName()) // haha haha

组合继承的优点

  1. 避免了原型链继承的共享属性问题(每个子类实例都有自己的属性副本,不会共享父类实例中的引用类型属性。)
  2. 可以继承父类原型上的方法(子类不仅继承了父类的实例属性,还可以继承父类原型上的方法,避免了重复定义方法的问题。)
  3. 灵活性高(可以在子类构造函数中调用父类构造函数时传递参数,确保父类初始化逻辑正常工作。)

组合继承的缺点

  1. 调用两次父类构造函数(组合继承的主要问题是它会调用两次父类构造函数:一次是在创建子类原型时 (new Fun1()),另一次是在子类构造函数中 (Fun1.call(this, 'haha'))。这会导致不必要的性能开销,尤其是在父类构造函数中有复杂初始化逻辑或大量计算时。)
  2. 原型对象的冗余属性(由于 Fun2.prototype = new Fun1(),子类的原型对象会包含父类实例的所有属性,这可能会导致不必要的内存占用。)

4.原型式继承

let parent = {name: 'parent',friends: [1, 2, 3],getName: function () {return this.name},
}
let child = Object.create(parent)
child.name = 'child'
child.friends.push(666) 
console.log(parent.getName(), child.getName()) // parent child
console.log(parent.friends, child.friends) // [1, 2, 3, 666] [1, 2, 3, 666]

原型式继承的弊端

  1. 共享引用类型属性(如果父对象中的属性是引用类型(如数组、对象),所有子对象会共享这些属性。修改一个子对象的引用类型属性会影响到其他子对象。
  2. 无法传递参数(原型式继承不能像构造函数继承那样在创建子对象时传递参数给父对象的初始化逻辑。)
  3. 缺乏构造函数支持(原型式继承没有构造函数的概念,因此无法像类或构造函数那样进行复杂的初始化操作。
  4.  难以扩展和维护(使用原型式继承的代码结构相对简单,但在大型项目中可能会导致代码难以扩展和维护。特别是当需要添加更多复杂的功能或逻辑时,原型式继承的方式显得不够灵活。
  5. 性能问题(由于所有子对象共享父对象的属性和方法,查找属性或方法时需要遍历原型链,这可能会影响性能,尤其是在多层继承的情况下。

5.寄生式继承

let parent = {name: 'parent',friends: [1, 2, 3],getName: function () {return this.name},
}
function clone(params) {let copyChild = Object.create(params)copyChild.getFriends = function () {return this.friends}return copyChild
}let child = clone(parent)
child.name = 'child'
child.friends.push(999)console.log(parent.friends, child.friends) // [1, 2, 3, 999] [1, 2, 3, 999]
console.log(child.getFriends())

寄生式继承的弊端

  1. 代码复杂度增加(寄生式继承增加了代码的复杂性,因为它引入了一个额外的函数来封装继承逻辑。这使得代码更难理解和维护,尤其是在大型项目中。
  2. 共享引用类型属性(尽管寄生式继承可以增强对象,但它仍然无法解决原型式继承中的共享引用类型属性问题。所有子对象会共享父对象中的引用类型属性,修改一个子对象的引用类型属性会影响到其他子对象。
  3. 缺乏构造函数支持(寄生式继承没有构造函数的概念,因此无法像类或构造函数那样进行复杂的初始化操作。每次创建新对象时都需要调用封装函数,并且需要手动传递参数。
  4. 性能问题(由于每次创建新对象时都需要调用封装函数并执行额外的逻辑,这可能会导致性能开销,尤其是在频繁创建对象的情况下。
  5. 难以扩展和维护(寄生式继承的代码结构相对复杂,特别是在多层继承或需要添加更多功能时,代码会变得难以扩展和维护。此外,调试和理解这种继承模式也更加困难。

6.寄生组合式继承

function Parent() {this.name = 'parent'this.play = [1, 2, 3]
}Parent.prototype.getName = function () {return this.name
}function Child() {Parent.call(this) // 借用构造函数继承属性this.friends = 'child'
}function clone(parent, child) {child.prototype = Object.create(parent.prototype) // 设置子类原型为父类原型的副本child.prototype.constructor = child // 修复构造函数指针
}clone(Parent, Child)Child.prototype.getFriends = function () {return this.friends
}let person = new Child()
console.log(person.getName(), person.getFriends()) // parent child

寄生组合式继承:是一种高效的继承模式,结合了构造函数继承和原型链继承的优点,避免了它们各自的缺点。它确保了每个子类实例都有自己的属性副本,同时可以继承父类原型上的方法,并且不会调用两次父类构造函数。这种继承方式在现代 JavaScript 开发中非常常见,特别是在需要复杂继承结构的情况下。

7.通过Es6中 extends 关键字继承

class Parent {constructor() {this.name = 'Parent'this.play = [1, 2, 3]}getName() {return this.name}
}class Child extends Parent {constructor() {// 在子类构造函数中调用父类构造函数,确保继承父类的实例属性,允许子类覆盖或扩展父类的功能。super() this.friends = 'child'}getFriends() {return this.friends}
}

相当于是 寄生组合式继承 的语法糖,使用起来更简洁高效。

相关文章:

关于JS继承的七种方式和理解

1.原型链继承 function Fun1() {this.name parentthis.play [1, 2, 3] } function Fun2() {this.type child }Fun2.prototype new Fun1()let s1 new Fun2() let s2 new Fun2() s1.play.push(4) console.log(s1.play, s2.play) // [1, 2, 3, 4] [1, 2, 3, 4]可以看到两个…...

储能系统-系统架构

已更新系列文章包括104、61850、modbus 、单片机等,欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统(BESS) 架构 电池储能系统主要包括、电池、pcs、本地控制…...

AI智算-k8s部署DeepSeek Janus-Pro-7B 多模态大模型

文章目录 简介环境依赖模型下载下载Janus库GPU环境镜像模型manifest调用Janus多模态文生图 简介 DeepSeek Janus Pro 作为一款强大的多模态理解与生成框架,正在成为研究人员和开发者的热门选择。本文将详细介绍如何在云原生k8s环境中部署配置和使用 DeepSeek Janus…...

【截图】selenium自动通过浏览器截取指定元素div的图片

【截图】selenium自动通过浏览器截取指定元素div的图片 思路 截取完整网页截图 通过元素的坐标 截图到指定位置的图片 前提是已经获取到 driver 了 # 定位目标divtarget_div driver.find_element(By.CLASS_NAME, headlines-right)# 获取div的位置和大小location target_div…...

如何导入第三方sdk | 引入第三方jar 包

0. 背景1. 上传私有仓库2. 使用本地文件系统 0. 背景 对接一些第三方功能,会拿到第三方的sdk,也就是jar包,如何导入呢 1. 上传私有仓库 最好的方式就是将第三方jar包,上传到私有的仓库,这样直接正常在pom引用即可如果只…...

HarmonyOS 5.0应用开发——ContentSlot的使用

【高心星出品】 文章目录 ContentSlot的使用使用方法案例运行结果 完整代码 ContentSlot的使用 用于渲染并管理Native层使用C-API创建的组件同时也支持ArkTS创建的NodeContent对象。 支持混合模式开发,当容器是ArkTS组件,子组件在Native侧创建时&#…...

C#常用集合优缺点对比

先上结论&#xff1a; 在C#中&#xff0c;链表、一维数组、字典、List<T>和ArrayList是常见的数据集合类型&#xff0c;它们各有优缺点&#xff0c;适用于不同的场景。以下是它们的比较&#xff1a; 1. 一维数组 (T[]) 优点&#xff1a; 性能高&#xff1a;数组在内存中…...

基于CLIP视觉语言大模型的行人重识别方法的简单框架设计

以下是一个基于CLIP视觉语言大模型的行人重识别方法的简单框架设计&#xff0c;用于数据集测试。我们将使用torch和clip库&#xff0c;假设数据集是一个包含行人图像的文件夹结构&#xff0c;每个子文件夹代表一个行人身份。 步骤概述 安装必要的库加载CLIP模型定义数据集类提…...

RabbitMQ 从入门到精通:从工作模式到集群部署实战(三)

文章目录 使用CLI管理RabbitMQrabbitmqctlrabbitmq-queuesrabbitmq-diagnosticsrabbitmq-pluginsrabbitmq-streamsrabbitmq-upgraderabbitmqadmin 使用CLI管理RabbitMQ RabbitMQ CLI 工具需要安装兼容的 Erlang/OTP版本。 这些工具假定系统区域设置为 UTF-8&#xff08;例如en…...

BurpSuite抓包与HTTP基础

文章目录 前言一、BurpSuite1.BurpSuite简介2.BurpSuite安装教程(1)BurpSuite安装与激活(2)安装 https 证书 3.BurpSuite使用4.BurpSuite资料 二、图解HTTP1.HTTP基础知识2.HTTP客户端请求消息3.HTTP服务端响应消息4.HTTP部分请求方法理解5.HTTPS与HTTP 总结 前言 在网络安全和…...

SQL Server 数据库迁移到 MySQL 的完整指南

文章目录 引言一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据 二、迁移工具的选择2.1 使用 MySQL Workbench2.2 使用第三方工具2.3 手动迁移 三、迁移步骤3.1 导出 SQL Server 数据库结构3.2 转换数据类型和语法3.3 导入 MySQL 数据库3.4 迁移数据3.5 迁移存…...

【大模型】DeepSeek与chatGPT的区别以及自身的优势

目录 一、前言二、核心技术对比2.1 模型架构设计2.1.1 ChatGPT的Transformer架构2.1.2 DeepSeek的混合架构 2.2 训练数据体系2.2.1 ChatGPT的数据特征2.2.2 DeepSeek的数据策略 三、应用场景对比3.1 通用场景表现3.1.1 ChatGPT的强项领域3.2.2 DeepSeek的专项突破 3.3 响应效率…...

DeepSeek:知识图谱与大模型参数化知识融合的创新架构

引言&#xff1a;AI 领域的融合趋势 在目前大模型与知识图谱作为两个重要的研究方向&#xff0c;各自展现出了强大的能力与潜力。大模型&#xff0c;凭借其在海量数据上的深度训练&#xff0c;拥有强大的语言理解与生成能力&#xff0c;能够处理多种自然语言处理任务&#xff0…...

ES6 迭代器 (`Iterator`)使用总结

Iterator&#xff08;迭代器&#xff09;是 ES6 引入的一种 接口&#xff0c;用于 顺序访问 可迭代对象&#xff08;Array、Set、Map、String、arguments、自定义对象等&#xff09;。 Iterator&#xff08;迭代器&#xff09;的作用有三个&#xff1a; 为各种数据结构提供一个…...

信用修复和失联修复的区别

失联修复和信用修复是两个不同的概念&#xff0c;在目的、操作方式和应用场景上都有所区别。 失联修复 失联修复主要是指在金融催收行业中&#xff0c;当债务人的联系方式&#xff08;通常是手机号码&#xff09;发生改变&#xff0c;导致无法联系到债务人时&#xff0c;催收公…...

2025蓝桥杯JAVA编程题练习Day3

1.黛玉泡茶【算法赛】 问题描述 话说林黛玉闲来无事&#xff0c;打算在潇湘馆摆个茶局&#xff0c;邀上宝钗、探春她们一起品茗赏花。黛玉素来讲究&#xff0c;用的茶杯也各有不同&#xff0c;大的小的&#xff0c;高的矮的&#xff0c;煞是好看。这不&#xff0c;她从柜子里…...

[论文阅读] Knowledge Fusion of Large Language Models

Knowledge Fusion of Large Language Models (FuseLLM) Methodology 整体Pipeline如下图所示 不同的动物代表不同的LLM。左边第一&#xff0c;第二分别是Ensemble以及Weight Merging方法。最右侧为本文提出的FuseLLM。 Ensemble: 融合多个models的预测结果&#xff0c;比如…...

deepseek来讲lua

Lua 是一种轻量级、高效、可嵌入的脚本语言&#xff0c;广泛应用于游戏开发、嵌入式系统、Web 服务器等领域。以下是 Lua 的主要特点和一些基本概念&#xff1a; 1. 特点 轻量级&#xff1a;Lua 的核心非常小&#xff0c;适合嵌入到其他应用程序中。高效&#xff1a;Lua 的执…...

探索 Spring Cloud Alibaba:开启微服务架构新时代

一、引言 在当今数字化浪潮中&#xff0c;软件系统的规模和复杂度不断攀升&#xff0c;传统的单体架构逐渐难以满足快速迭代、高并发处理以及灵活扩展的需求。微服务架构应运而生&#xff0c;它将一个大型的应用拆分成多个小型、自治的服务&#xff0c;每个服务专注于特定的业务…...

【数据结构】(6) LinkedList 链表

一、什么是链表 1、链表与顺序表对比 不同点LinkedListArrayList物理存储上不连续连续随机访问效率O(N)O(1&#xff09;插入、删除效率O(1)O(N) 3、链表的分类 链表根据结构分类&#xff0c;可分为单向/双向、无头结点/有头节点、非循环/循环链表&#xff0c;这三组每组各取…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...

java 局域网 rtsp 取流 WebSocket 推送到前端显示 低延迟

众所周知 摄像头取流推流显示前端延迟大 传统方法是服务器取摄像头的rtsp流 然后客户端连服务器 中转多了&#xff0c;延迟一定不小。 假设相机没有专网 公网 1相机自带推流 直接推送到云服务器 然后客户端拉去 2相机只有rtsp &#xff0c;边缘服务器拉流推送到云服务器 …...

【Pandas】pandas DataFrame dropna

Pandas2.2 DataFrame Missing data handling 方法描述DataFrame.fillna([value, method, axis, …])用于填充 DataFrame 中的缺失值&#xff08;NaN&#xff09;DataFrame.backfill(*[, axis, inplace, …])用于**使用后向填充&#xff08;即“下一个有效观测值”&#xff09…...