深入探究 JavaScript 中的继承方式

深入探究 JavaScript 中的继承方式

引言

在 JavaScript 的世界里,继承是构建复杂应用程序的重要基石。它允许我们在已有代码的基础上进行扩展和复用,从而提高开发效率。今天,就让我们一同深入探讨 JavaScript 中多种继承方式的奥秘。

在 JavaScript 中,继承的方式多种多样,每种方式都有其独特的优势和适用场景。我们先来看一种常见的方式:原型传递。

function Game (name, type) {
    this.name = name;
    this.type = type;
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}

// 现在有一个对象 LOL
function LOL() {}
// 他需要继承 Game 的属性和方法
// 原型传递
LOL.prototype = new Game('LOL', 'MOBA');
LOL.prototype.constructor = LOL;
const lol = new LOL();
lol.play(); // LOL MOBA 游戏正在玩

这种方式简单直接,通过将父类的实例赋给子类的原型,实现了属性和方法的继承。但它也存在一些问题。

重写原型法存在的问题

父类属性一旦赋值给子类的原型属性,此时就属于子类的共享属性,会导致继承者之间实例的篡改。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}

// 现在有一个对象 LOL
function LOL() {}
// 他需要继承 Game 的属性和方法
// 原型传递
LOL.prototype = new Game('LOL', 'MOBA');
LOL.prototype.constructor = LOL;
const lol = new LOL();
const lol2 = new LOL();
lol.play(); // LOL MOBA 游戏正在玩
lol2.play(); // LOL MOBA 游戏正在玩
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(lol2.skin); // ['史诗', '至臻']

而且在实例化时无法向父类传递参数,即无法创造一个不同的 LOL。

为了解决这些问题,我们引出了构造函数继承(经典继承)。

构造函数继承(经典继承)

通过在子类的构造函数中调用父类的构造函数,解决了实例的独立性。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}
// 现在有一个对象 LOL
function LOL(name, type) {
    Game.call(this, name, type);
}
const lol = new LOL('LOL', 'MOBA');
const wzry = new LOL('wzry', 'MOBA');
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(wzry.skin); // ['史诗']
// 构造函数继承解决了实例的独立性

lol.play(); // lol.play is not a function
wzry.play(); // wzry.play is not a function

然而,这种方式又带来了新的问题,即继承了父类的属性和方法,但没有原型传递,无法使用原型共享。

接着,我们来看原型链继承(组合继承)。

原型链继承(组合继承)

结合了原型传递和构造函数继承的优点。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}
// 现在有一个对象 LOL
function LOL(name, type) {
    // 第一次执行
    Game.call(this, name, type);
}
// 第二次执行
LOL.prototype = new Game();
const lol = new LOL('LOL', 'MOBA');
const wzry = new LOL('wzry', 'MOBA');
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(wzry.skin); // ['史诗']
// 构造函数继承解决了实例的独立性

lol.play(); // LOL MOBA 游戏正在玩
wzry.play(); // wzry MOBA 游戏正在玩

但它又存在一个问题,父类的构造函数会被执行两边。

最后,我们介绍寄生组合继承来解决这个问题。

寄生组合继承

通过使用 Object.create() 方法,避免了父类构造函数的重复执行。

function Game (name, type) {
    this.name = name;
    this.type = type;
    this.skin = ['史诗'];
}
Game.prototype.play = function() {
    console.log(`${this.name} ${this.type} 游戏正在玩`);
}
// 现在有一个对象 LOL
function LOL(name, type) {
    Game.call(this, name, type);
}
LOL.prototype = Object.create(Game.prototype);
const lol = new LOL('LOL', 'MOBA');
const wzry = new LOL('wzry', 'MOBA');
lol.skin.push('至臻');
console.log(lol.skin); // ['史诗', '至臻']
console.log(wzry.skin); // ['史诗']
// 构造函数继承解决了实例的独立性

lol.play(); // LOL MOBA 游戏正在玩
wzry.play(); // wzry MOBA 游戏正在玩

结尾

通过对 JavaScript 中各种继承方式的深入探讨和代码示例,我们可以看到每种方式都有其独特的优势和适用场景。在实际开发中,我们需要根据具体需求选择合适的继承方式,以构建高效、可维护的 JavaScript 应用程序。希望本文能为你在 JavaScript 继承的探索之路上提供有益的参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/916034.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 3.3.5 试用CRaC,启动速度提升3到10倍

文章目录 一 CRaC是什么二 CRaC的原理三 CRaC 的应用场景四 支持版本五 实践 今天和小伙伴们来聊一个稍微新一点的技术话题—CRaC。 CRaC(Coordinated Restore at Checkpoint,检查点协调恢复)是一个 OpenJDK 项目,旨在解决 Java 应…

大模型本地部署:Ollama+MaxKB 部署本地知识库

前言 本文我们介绍另外一种部署本地知识库的方案: Ollama MaxKB 相对来说,容易安装且功能较完善,30 分钟内即可上线基于本地大模型的知识库问答系统,并嵌入到第三方业务系统中。 缺点是如果你的电脑配置不高,问题…

Nuxt.js 应用中的 schema:beforeWrite 事件钩子详解

title: Nuxt.js 应用中的 schema:beforeWrite 事件钩子详解 date: 2024/11/14 updated: 2024/11/14 author: cmdragon excerpt: schema:beforeWrite 钩子是 Vite 提供的一个功能强大的生命周期钩子,允许开发者在 JSON Schema 被写入之前执行自定义操作。利用这个钩子,您可以…

Scrapy爬取heima论坛所有页面内容并保存到数据库中

前期准备: Scrapy入门_win10安装scrapy-CSDN博客 新建 Scrapy项目 scrapy startproject mySpider03 # 项目名为mySpider03 进入到spiders目录 cd mySpider03/mySpider03/spiders 创建爬虫 scrapy genspider heima bbs.itheima.com # 爬虫名为heima &#…

MacBook 下载vscode不能被解压及打开的解决方案

mac 下载vscode不能被解压解决方案如下 1.下载全能解压 进行解压 解压完如果提示 已损坏,无法打开。 您应该将它移到废纸篓 2.允许“任何来源”开启 开启终端输入 sudo spctl --master-disable回车 3. 扩展文件属性 先输入 sudo xattr -r -d com.apple.quaran…

【AI声音克隆整合包及教程】第二代GPT-SoVITS V2:技术、应用与伦理思考

一、引言 在当今科技迅速发展的时代,声音克隆技术成为人工智能领域的一个备受瞩目的分支。GPT-SoVITS V2作为一种声音克隆工具,正逐渐进入人们的视野,它在多个领域展现出巨大的潜力,同时也引发了一系列值得深入探讨的问题。本文旨…

DAY113代码审计-PHPTP框架微P系统漏审项目等

一、环境安装 导入数据 Debug 版本信息收集 一、不安全写法的sql注入(拼接写法绕过预编译机制) 1、Good.php的不安全写法 2、查找可以参数 3、找路由关系 application/index/controller/Goods.php http://172.19.1.236:8833/index.php/index/goods/aj…

35.3K+ Star!PhotoPrism:一款基于AI的开源照片管理工具

PhotoPrism 简介 PhotoPrism[1] 是一个为去中心化网络设计的AI照片应用,它利用最新技术自动标记和查找图片,实现自动图像分类与本地化部署,你可以在家中、私有服务器或云端运行它。 项目特点 主要特点 浏览所有照片和视频,无需担心RAW转换、重复项或视频格式。 使用强大的…

【CUDA】了解GPU架构

目录 一、初步认识 二、Fermi架构 三、Kepler 架构 3.1 动态并行 3.2 Hyper-Q 一、初步认识 SM(Streaming Multiprocessors)是GPU架构中非常重要的部分,GPU硬件的并行性就是由SM决定的。以Fermi架构为例,其包含以下主要组成…

鸿蒙HarmonyOS 网络请求获取数据Http

注意的是;要为接口返回值指定类型 ,以及定义接口数据类型 index.ets import { http } from kit.NetworkKit;interface createAtType {date: number,}interface dataListType {createAt: createAtType;imgUrl: }Component export default struct TabBar {State dat…

Windows VSCode .NET CORE WebAPI Debug配置

1.安装C#插件 全名C# for Visual Studio Code,选择微软的 2. 安装C# Dev Kit插件 全名C# Dev Kit for Visual Studio Code,同样是选择微软的 3.安装Debugger for Unity 4.配置launch.json 文件 {"version": "0.2.0","config…

Odoo:免费开源的流程制造行业ERP管理系统

概述 聚焦流程制造连续性生产的特性,提供集成PLMERPMESBI的一体化解决方案,涵盖计划、生产、质量、配方、供销、库存、成本、设备、资金管理等业务领域的整体性解决方案 行业的最新洞察&行业典型痛点 一、生产过程需要精细化控制 需要在各种制约…

ERP管理系统(源码+文档+部署+讲解)

本文将深入解析“ERP管理系统”的项目,探究其架构、功能以及技术栈,并分享获取完整源码的途径。 系统概述 ERP管理系统是一款全面的资源规划软件,旨在通过集成各种业务流程和功能模块来提高管理效率和决策质量。该系统覆盖了从基础设置、供…

mysql每日一题(上升的温度,date数据的计算)

日期之间的运算 日期类型的加法运算 data_add(now_data,interval 1 month) select date_add(now(), interval 1 day); -- 加1天 select date_add(now(), interval 1 hour); -- 加1小时 select date_add(now(), interval 1 minute); -- 加1分钟 select date_add(now(), inter…

CTF攻防世界小白刷题自学笔记13

1.fileinclude,难度:1,方向:Web 题目来源:宜兴网信办 题目描述:无 给一下题目链接:攻防世界Web方向新手模式第16题。 打开一看给了很多提示,什么language在index.php的第九行,flag在flag.php中,但事情显…

FFmpeg 4.3 音视频-多路H265监控录放C++开发十三.2:avpacket中包含多个 NALU如何解析头部分析

前提: 注意的是:我们这里是从avframe转换成avpacket 后,从avpacket中查看NALU。 在实际开发中,我们有可能是从摄像头中拿到 RGB 或者 PCM,然后将pcm打包成avframe,然后将avframe转换成avpacket&#xff0…

LabVIEW环境监测系统

随着环境问题的日益严重,环境参数的实时监测成为保障公共健康和生态平衡的重要手段。开发了一款基于LabVIEW开发的环境监测系统,能够对大气中的温度、湿度及二氧化硫浓度进行实时监测,并提供数据存储和超阈值报警功能。 系统组成 本系统由下…

【视觉SLAM】2-三维空间刚体运动的数学表示

读书笔记:学习空间变换的三种数学表达形式。 文章目录 1. 旋转矩阵1.1 向量运算1.2 坐标系空间变换1.3 变换矩阵与齐次坐标 2. 旋转向量和欧拉角2.1 旋转向量2.2 欧拉角 3. 四元数 1. 旋转矩阵 1.1 向量运算 对于三维空间中的两个向量 a , b ∈ R 3 a,b \in \R^3 …

SystemVerilog学习笔记(十):进程/细粒度进程控制

进程 进程或线程是作为独立实体执行的任何代码片段。fork-join块创建并行运行的不同线程。在下面的图-1中,可以看到进程的类型和进程控制。 序号进程描述1.fork-join只有所有子线程执行完毕时,父线程才会执行。2.fork-join_any只有任何一个子线程执行完…

【Visual Studio系列教程】如何在 VS 上编程?

上一篇博客中,我们介绍了《什么是 Visual Studio?》。本文,我们来看第2篇《如何在 VS 上编程?》。阅读本文大约10 分钟。我们会向文件中添加代码,了解 Visual Studio 编写、导航和了解代码的简便方法。 本文假定&…