JavaScript class和继承的原理
(对于不屈不挠的人来说,没有失败这回事。——俾斯麦)
class
相关链接
MDN链接
有关类的详细描述
关于构造函数,原型和原型链的说明
类的概述
类是用于创建对象的模板。他们用代码封装数据以处理该数据。JS 中的类建立在原型上,但也具有某些语法和语义未与 ES5 类相似语义共享。
实际上,类是“特殊的函数”,就像你能够定义的函数表达式和函数声明一样,类语法有两个组成部分:类表达式和类声明。
JavaScript面向对象编程
在es6之前,面向对象的编程方式都是创建函数和实例化构造函数来达到目的,但这和传统的面向对象编程,比如和c++和,java的差异很大。我们先了解以下函数的面向对象编程方式
函数
创建一个普通函数animal
普通函数是可以当作函数方法来使用,直接执行业务操作后返回
const animal = function (name, color) {return `动物名称:${name} - 动物毛发颜色:${color}`
};
console.log(animal('刺猬', '褐色'));
创建一个构造函数Animal
构造函数是一种特殊的函数,类似传统编程的类,主要用来初始化对象,即为对象成员变量赋初始值。它总与 new 一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
使用构造函数需要注意以下两点
- 构造函数和传统类的意义相同,首字母要大写
- 构造函数必须实例化才有意义,也就是new
而new的过程中也做了以下事情
- 在内存中创建一个新的空对象。
- 让 this 指向这个新的对象。
- 执行构造函数里面的代码,给这个新对象添加属性和方法。
- 返回这个新对象(所以构造函数里面不需要 return )。
构造函数的成员属性又分为静态属性和实例化属性。
实例化属性只有实例化对象后才能访问,比如hedgehogData。
静态属性不需要实例化对象就可以访问,比如height。
const Animal = function (name, color) {this.name = name;this.color = color;this.getAnimal = function () {return `动物名称:${this.name} - 动物毛发颜色:${this.color}`}
};
const hedgehog = new Animal('刺猬', '褐色');
const hedgehogData = hedgehog.getAnimal();
console.log(hedgehogData);
Animal.height = 50;
console.log(Animal.height);
扩展构造函数
如果后续要扩展构造函数,目前我们已经直到可以继续通过编写this.'方法名’的方式来达到目的。但这样对代码有较高的侵入性,会导致构造函数越来越臃肿,并且会导致无效的内存上涨。
const Animal = function (name, color) {this.name = name;this.color = color;this.getAnimal = function () {return `动物名称:${this.name} - 动物毛发颜色:${this.color}`}
};
const hedgehog = new Animal('刺猬', '褐色');
const dog = new Animal('狗', '黑色');
console.log(hedgehog.getAnimal === dog.getAnimal); // false 每个实例化对象都有自己的内存地址
但JavaScript还有原型链和原型这两个特性
关于原型和原型链的说明
我们可以通过在原型上自定义的方式进行扩展,这样就可以把成员属性定义在构造函数内,方法通过原型进行扩展。
const Animal = function (name, color) {this.name = name;this.color = color;
};
Animal.prototype.getAnimal = function () {return `动物名称:${this.name} - 动物毛发颜色:${this.color}`
}
const hedgehog = new Animal('刺猬', '褐色');
const dog = new Animal('狗', '黑色');
console.log(hedgehog.getAnimal === dog.getAnimal); // true 原型上的方法和属性由对象直接继承,也就是可以共享访问,所以为true
继承
函数的继承
通过上文我们了解到,如果还想做函数的继承,那么有以下方式
- 继承原型
- 使用call方法继承
- 使用apply方法继承
其步骤较为繁琐,后期维护复杂,并且和传统的面向对象编程方式不同,违背了面向对象变成的理念。
class类
基于以上问题,es6推出了class类语法糖的新规范,写法和传统面向对象类编程的方式更接近。
class Animal {constructor(name, color) {this.name = name;this.color = color;}getAnimal () {return `动物名称:${this.name} - 动物毛发颜色:${this.color}`;}
}
const hedgehog = new Animal('刺猬', '褐色');
const dog = new Animal('狗', '黑色');
console.log(hedgehog.getAnimal === dog.getAnimal); // true
class继承 extends
其中用到了super关键字
MDN super解释
class Animal {constructor(name, color) {this.name = name;this.color = color;}getAnimal () {return `动物名称:${this.name} - 动物毛发颜色:${this.color}`;}
}
class Cat extends Animal {constructor(name, color) {super();this.name = name;this.color = color;}
}
const dog = new Animal('狗', '黑色');
const cat = new Cat('猫', '橙色');
console.log(cat.getAnimal()); // 动物名称:猫 - 动物毛发颜色:橙色
console.log(cat.getAnimal === dog.getAnimal); // true
class编译后的结果
babel网站,可以在线编辑
我们将上面的class代码编译成nodejs原生的commonjs规范。
"use strict";function _inheritsLoose(subClass, superClass) {subClass.prototype = Object.create(superClass.prototype);subClass.prototype.constructor = subClass;_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {_setPrototypeOf = Object.setPrototypeOf? Object.setPrototypeOf.bind(): function _setPrototypeOf(o, p) {o.__proto__ = p;return o;};return _setPrototypeOf(o, p);
}
var Animal = /*#__PURE__*/ (function () {function Animal(name, color) {this.name = name;this.color = color;}var _proto = Animal.prototype;_proto.getAnimal = function getAnimal() {return "name:" + this.name + " - color:" + this.color;};return Animal;
})();
var Cat = /*#__PURE__*/ (function (_Animal) {_inheritsLoose(Cat, _Animal);function Cat(name, color) {var _this;_this = _Animal.call(this) || this;_this.name = name;_this.color = color;return _this;}return Cat;
})(Animal);
var dog = new Animal("dog", "black");
var cat = new Cat("cat", "orange");
console.log(cat.getAnimal());
console.log(cat.getAnimal === dog.getAnimal);
可以看出class只是语法糖,其类的初始化实际上就是构造函数,extends其内部也依然是原型的继承。
对比
通过原生函数和class的对比,class语法糖的写法更接近传统面向对象编程的方式,也更比原生函数容易开发,方便后期维护。
如何实现多继承
传统的面向对象编程语言都只是单继承,这是因为在大多数业务场景下通过继承能提高开发效率,提高程序性能,提高代码的复用率。但在业务复杂,项目庞大的情况下,也出现了一些缺陷。
- 父子类之间的耦合度过高,父类的改变直接影响到子类。
- 子类的灵活性降低,父类中有些子类不需要或和子类冲突的属性或方法
- 当父类的属性或方法改变时,子类也需要更改,严重时,还需要重构子类
- …
当然,有些业务场景下也确实需要多继承,但class是不支持多继承的,extends后只能编写一个父类。
但我们可以通过原生原型的方式来达到多继承的目的。
function more_father () {this.f_name = "父亲";this.f_age = 55;this.f_address = "北京朝阳"
};more_father.prototype.f_method = function () {return this.f_name + this.f_age + this.f_address;
};function more_mother () {this.m_name = "母亲";this.m_age = 53;this.m_address = "北京朝阳";
};more_mother.prototype.m_method = function () {return this.m_name + this.m_age + this.m_address;
};function more_son () {this.s_name = "孩子";this.s_age = 22;this.s_address = "北京朝阳"
};more_son.prototype.s_method = function () {return this.s_name + this.s_age + this.s_address;
};more_son.prototype.f_pro = new more_father();
more_son.prototype.m_pro = new more_mother();
const _mores = new more_son();
console.log(_mores.f_pro.f_method());
相关文章:

JavaScript class和继承的原理
(对于不屈不挠的人来说,没有失败这回事。——俾斯麦) class 相关链接 MDN链接 有关类的详细描述 关于构造函数,原型和原型链的说明 类的概述 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JS 中的类建立在原型上…...

Playwright-python 自动化测试【Anaconda】环境配置
第一步:Anaconda的安装 安装Anaconda的好处,比prenv网速快,并且拥有独立的python环境,再也不用烦恼用哪个python好了。 Anaconda的下载页参见官网下载,Linux、Mac、Windows均支持。 https://mirrors.tuna.tsinghua.ed…...

攻防世界-web-simple js
题目描述:小宁发现了一个网页,但却一直输不对密码。(Flag格式为 Cyberpeace{xxxxxxxxx} ) 打开链接: 然后我们会发现不管我们输入什么密码,发现是都是这样的报错 1. 先用bp抓包看看,可以抓到这样的一串js脚本 看不懂…...
【SpringCloud】初始微服务
目录 一、单体架构 1、概念 2、优点 3、缺点 二、分布式架构 1、概念 2、优点 3、缺点 三、微服务 1、概念 2、优点 3、缺点 四、微服务技术对比 五、SpringCloud 六、服务拆分 1、注意事项 2、服务远程调用 一、单体架构 1、概念 业务的所有功能都集中到一个…...

均摊时间复杂度
均摊时间复杂度,它对应的分析方法,摊还分析(或者叫平摊分析) 均摊时间复杂度应用的场景比它更加特殊、更加有限 // array表示一个长度为n的数组// 代码中的array.length就等于nint[] array new int[n];int count 0;void insert…...

夏驰和徐策的解决数学问题思路——反证法
反证法是一种证明方法,它的基本思路是通过假设某个结论不成立,然后构造出一个矛盾的情况来推导出原先假设的结论是成立的。 具体来说,反证法一般包含以下步骤: 1. 假设所要证明的命题不成立。 2. 通过这个假设,构造…...

面向开发人员的 ChatGPT 提示词教程 - ChatGPT Prompt Engineering for Developers
面向开发人员的 ChatGPT 提示词教程 - ChatGPT Prompt Engineering for Developers 1. 指南(原文: Guidelines)1-1. 提示的指南(原文: Guidelines for Prompting)1-2. 配置1-3. 提示语原则(原文: Prompting Principles)原则 1: 写出清晰而具体的指示(原文: Write clear and spe…...

虹科方案|使用 HK-TRUENAS支持媒体和娱乐工作流程-1
一、摘要 开发和交付能够随时随地触及受众的媒体内容变得越来越重要和复杂。 在当今高度互联、娱乐驱动的世界中,媒体和娱乐 (M&E) 公司需要保持竞争力才能取得成功。 这些组织需要制作各种不同格式的信息和娱乐内容,以便在移动设备、台式机、工作站…...

DDR5内存彻底白菜价,国外大厂却整出了比着火更离谱的骚操作
今年的 PC 硬件市场,似乎出现了明显两极分化现象。 一边是 N、A 两家新显卡价格高高在上,摆明了不坑穷人。 另一边固态硬盘、内存条又在疯狂互卷不断杀价。 四五百元的 2TB SSD,二百元的 16G 内存条早已见怪不怪。 要说面世多年的 PCIe 3.0…...

Linux网络——Shell编程之函数
Linux网络——Shell编程之函数 一、概述二、定义函数的格式1.格式一2.格式二 三、函数的查看和删除1.查看 declare2.删除 declare 四、函数的返回值1.return 返回值2.echo 返回值 五、函数的参数传入与变量范围1.函数的传参2.函数变量的作用范围 六、函数的应用1.阶乘2.递归目录…...
GQCNN+PointNetGPD思路和问题--chatGPT
有很多算法是通过神经网络来预测机械臂抓手的抓取位置,其中一些算法需要点云数据作为输入,例如: PointNetGPD:PointNetGPD是一个端到端的基于点云的抓取姿态检测算法。它使用了一个PointNet架构来处理点云输入,并输出每…...

Mysql索引(2):索引结构
1 概述 MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种: 索引结构描述BTree索最常见的索引类型,大部分引擎都支持 B 树索引 Hash索引 底层数据结构是用哈希表实现的, 只有精确匹配索引列的…...
Spring框架介绍和应用实践
Spring是一个开源的Java企业应用开发框架,它通过依赖注入和面向切面编程等技术实现了轻量级、松散耦合、可测试和可扩展的应用开发。本文将介绍Spring框架的基本原理和核心功能,以及在实际项目中如何使用Spring框架进行应用开发。 Spring框架基本原理 …...

IO 流学习总结
一:IO 流的概述 1. 什么是 IO 流? 存储和读取数据的解决方法 I:input O:output 流:像水流一样传输数据 2. IO 流的作用? 用于读写数据(本地文件,网络) 3. IO 流按…...
PowerToys——免费、强大、高效的微软官方效率提升工具集,办公学习宝藏软件
名人说:博观而约取,厚积而薄发。——宋苏轼 Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、简单介绍1、PowToys是什么?2、它的功能有哪些?二、下载安装三、功能示例1、始终置顶2、唤醒3、颜色选取器(取色)4、FancyZones(窗口布局)5、File Locksmith6、…...

【C++】 类基础汇总(类封装,构造、析构函数...)
目录 前言 正文 类封装 为什么要进行类封装 概念 访问修饰符 构造函数 概念 特点 析构函数 概念 特点 再谈面向过程与面向对象 面向过程 代码举例 面向对象 代码举例 结语 下期预告 前言 在学习过【C语言进阶C】 C基础--让你丝滑的从C语言进阶到C 之后&am…...

BM61-矩阵最长递增路径
题目 给定一个 n 行 m 列矩阵 matrix ,矩阵内所有数均为非负整数。 你需要在矩阵中找到一条最长路径,使这条路径上的元素是递增的。并输出这条最长路径的长度。 这个路径必须满足以下条件: 对于每个单元格,你可以往上ÿ…...

selenium——unittest框架
目录 一、unittest框架基本介绍二、unittest框架解析三、unittest框架使用方法1.测试固件2.测试套件3.用例的执行顺序4.忽略测试用例中的方法5.unittest断言6.HTML报告生成 一、unittest框架基本介绍 在进行selenium IDE脚本录制导出的脚本中,我们发现其中多了很多…...
matlab频谱分析详解
频谱分析是一种用于分析信号频率特征的方法,常用于信号处理、音乐分析、谐波产生等领域。MATLAB是一种功能强大的数字信号处理软件,提供了许多用于频谱分析的函数和工具箱。 本文将介绍如何使用MATLAB进行频谱分析,包括信号预处理、选择合适…...
用layui写用户登录页面遇到的问题
用layui写用户登录页面遇到的问题 1.在layui-row下面的layui-col-md还是换行 原因:link标签和script标签中的type属性没写,导致应该是script或者这个css没有识别出来 解决办法:link标签里面加上type为text/css, script标签中加上type为 2…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
React核心概念:State是什么?如何用useState管理组件自己的数据?
系列回顾: 在上一篇《React入门第一步》中,我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目,并修改了App.jsx组件,让页面显示出我们想要的文字。但是,那个页面是“死”的,它只是静态…...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...