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

JavaScript class和继承的原理

(对于不屈不挠的人来说,没有失败这回事。——俾斯麦)

在这里插入图片描述

class

相关链接

MDN链接
有关类的详细描述
关于构造函数,原型和原型链的说明

类的概述

类是用于创建对象的模板。他们用代码封装数据以处理该数据。JS 中的类建立在原型上,但也具有某些语法和语义未与 ES5 类相似语义共享。
实际上,类是“特殊的函数”,就像你能够定义的函数表达式和函数声明一样,类语法有两个组成部分:类表达式和类声明。

JavaScript面向对象编程

在es6之前,面向对象的编程方式都是创建函数和实例化构造函数来达到目的,但这和传统的面向对象编程,比如和c++和,java的差异很大。我们先了解以下函数的面向对象编程方式

函数

创建一个普通函数animal

普通函数是可以当作函数方法来使用,直接执行业务操作后返回

const animal = function (name, color) {return `动物名称:${name} - 动物毛发颜色:${color}`
};
console.log(animal('刺猬', '褐色'));

创建一个构造函数Animal

构造函数是一种特殊的函数,类似传统编程的类,主要用来初始化对象,即为对象成员变量赋初始值。它总与 new 一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
使用构造函数需要注意以下两点

  1. 构造函数和传统类的意义相同,首字母要大写
  2. 构造函数必须实例化才有意义,也就是new

而new的过程中也做了以下事情

  1. 在内存中创建一个新的空对象。
  2. 让 this 指向这个新的对象。
  3. 执行构造函数里面的代码,给这个新对象添加属性和方法。
  4. 返回这个新对象(所以构造函数里面不需要 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 

继承

函数的继承
通过上文我们了解到,如果还想做函数的继承,那么有以下方式

  1. 继承原型
  2. 使用call方法继承
  3. 使用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语法糖的写法更接近传统面向对象编程的方式,也更比原生函数容易开发,方便后期维护。

如何实现多继承

传统的面向对象编程语言都只是单继承,这是因为在大多数业务场景下通过继承能提高开发效率,提高程序性能,提高代码的复用率。但在业务复杂,项目庞大的情况下,也出现了一些缺陷

  1. 父子类之间的耦合度过高,父类的改变直接影响到子类。
  2. 子类的灵活性降低,父类中有些子类不需要或和子类冲突的属性或方法
  3. 当父类的属性或方法改变时,子类也需要更改,严重时,还需要重构子类

  4. 当然,有些业务场景下也确实需要多继承,但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 ,矩阵内所有数均为非负整数。 你需要在矩阵中找到一条最长路径,使这条路径上的元素是递增的。并输出这条最长路径的长度。 这个路径必须满足以下条件: 对于每个单元格,你可以往上&#xff…...

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 Navigation)

导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)

Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

背包问题双雄:01 背包与完全背包详解(Java 实现)

一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...

大模型真的像人一样“思考”和“理解”吗?​

Yann LeCun 新研究的核心探讨:大语言模型(LLM)的“理解”和“思考”方式与人类认知的根本差异。 核心问题:大模型真的像人一样“思考”和“理解”吗? 人类的思考方式: 你的大脑是个超级整理师。面对海量信…...

若依项目部署--传统架构--未完待续

若依项目介绍 项目源码获取 #Git工具下载 dnf -y install git #若依项目获取 git clone https://gitee.com/y_project/RuoYi-Vue.git项目背景 随着企业信息化需求的增加,传统开发模式存在效率低,重复劳动多等问题。若依项目通过整合主流技术框架&…...

第14节 Node.js 全局对象

JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。 在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局…...

Flask和Django,你怎么选?

Flask 和 Django 是 Python 两大最流行的 Web 框架,但它们的设计哲学、目标和适用场景有显著区别。以下是详细的对比: 核心区别:哲学与定位 Django: 定位: "全栈式" Web 框架。奉行"开箱即用"的理念。 哲学: "包含…...