当前位置: 首页 > 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;这三组每组各取…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...