JS中的OOP

news2024/12/26 23:42:32

JS中的OOP

OOP 为我们解决了什么问题?想象一下,我们希望为教师提供一个平台,每位注册的教师都可以提交分数,并为课程分配作业和其他内容。

如果有一个地方(在本例中是一个对象),可以访问所有教师的数据(例如他们的姓名、职业和班级列表)以及前面提到的那些功能,那就太好了。简而言之,就是将数据和方法封装或者捆绑在一起。

为了实现我们的目的,我们创建一个函数来接收教师的数据并返回一个包含这些数据的对象以及每个教师能够执行的方法。

const teacherCreator = (name: string, profession: string, classes: string[]) => {
  const newTeacher = {};
  newTeacher.name = name;
  newTeacher.profession = profession;
  newTeacher.classes = classes;

  newTeacher.submitMark = function(mark: number, studentId: number) {
    //....
    
    console.log(`学生${studentId} 的分数是${mark}`)
  }

  newTeacher.assignHomework = function(homework: string, classId: number) {
    // ....
  }
}

这是我们的teacherCreator功能演示。通过这种方式,我们实现了数据和方法的封装。但有一个问题值得我们考虑。

内存耗用大

假设我们在有 1000 名教师,我们的这些消耗内存方法会在每个教师对象中重复定义。

但是我们只想要一份函数副本。将所有方法都初始化在一个地方,并且每当我们尝试调用其中任何一个方法时,我们都从那里选择它并避免这种重复,这不是更有效吗?

我们可以在 JavaScript 中通过多种解决方案完成同样的事情。

方法一:工厂函数

我们可以将实现teacherCreator函数的方式更改为:

const teacherCreator = (name: string, profession: string, classes: string[]) => {
  const newTeacher = Object.create(teacherFunctionStore);
  newTeacher.name = name;
  newTeacher.profession = profession;
  newTeacher.classes = classes;

  // 返回一个对象
  return newTeacher;
}

// 创建一个对象包含所有方法
const teacherFunctionsStore = {
  submitMark: function(mark: number, studentId: number) {
    //....
    
    console.log(`学生${studentId} 的分数是${mark}`)
  },
  assignHomework: function(homework: string, classId: number) {
    // ....
  }
}


const teacher1 = teacherCreator('Leo', 'English', ['A1-English']);
teacher1.assignHomeWork('do workbook', 10)

在上面的代码块中,我们不会在每个教师对象上创建这些方法。我们只是有一个地方——另一个对象——来存储所有方法。现在的问题是 JavaScript 如何知道在哪里找到这些方法并执行它们。

JavaScript 如何执行这段代码?

下面我们将逐步指导如何在所有方法中执行此代码。一般来说,在 JavaScript 中执行时,每段代码所发生的情况都是完全相同的。

在这里插入图片描述

  1. JavaScript 会在全局内存中看到teacherCreator,它将把它创建为一个函数。顺便说一下,它不会进入函数内部。
  2. 接下来,它将看到我们的teacherFunctionStore对象,并使用其中的方法在全局内存中启动它。
  3. 代码的下一行是一个名teacher1为的变量,它将在全局内存中初始化,但尚未设置值。因此,JavaScript 将进入teacherCreator执行上下文中的函数内部。
  4. 在执行上下文内部 -每个函数调用都会创建一个新的执行上下文- 首先是将函数的参数设置在该执行上下文的本地内存中。
  5. Object.create()将为我们创建一个空对象。我们已经将teacherFunctionStore 传递给了它,因此它将使用该对象__proto__的属性来引用newTeacher对象。该参考在图中用红线突出显示。
const newTeacher = Object.create(teacherFunctionStore);
  1. 然后,我们将向对象添加属性并将其返回到全局内存中——设置teacher1的值。

JavaScript 现在如何调用这些方法?

现在的问题是teacher1.assignHomework()如何执行。这些方法不在对象本身内。

答案是非常清楚的。当我们调用对象的方法时,JavaScript 将首先查看该对象以查找该函数。如果找到它,它将执行它。在我们的例子中,它在我们的teacher1对象上找不到assignHomework。它应该抛出错误吗?当然不是。至少现在还不行。

JavaScript 不会很快放弃。如果属性或方法不在对象本身内部,它将在对象的__proto__属性中查找。

我们已经知道,我们的对象teacher1会通过__proto__链接到teacherFunctionStoreJavaScript会找到其中的方法并执行它。

方法2:构造函数

使用new关键字来实现我们的功能,该关键字可以自动为我们完成这些链接工作。

function TeacherCreator(name: string, profession: string, classes: string[]) {
  this.name = name;
  this.profession = profession;
  this.classes = classes;
}

TeacherCreator.prototype.submitMark = function(mark: number, studentId: number) {
    //....
     console.log(`学生${studentId} 的分数是${mark}`)
},

TeacherCreator.prototype.assignHomework = function(homework: string, classId: number) {
    // ....
}

const teacher1 = new TeacherCreator('Leo', 'English', ['A1-English']);
teacher1.assignHomeWork('do workbook', 10)

TeacherCreator构造函数前面的 new 关键字将为我们自动执行两件事:

  • 创建一个新的教师对象
  • 返回新创建的教师对象

构造函数如何使用 new 关键字在幕后执行?

在这里插入图片描述

  1. 第一行是定义TeacherCreator构造函数。JavaScript 中的每个函数也是一个对象。因此,这里我们有一个函数-对象组合,如上图所示。每当我们想要访问函数部分时,我们都使用()符号,而对于对象,我们使用.符号。
  2. 在接下来的代码行中,我们将在对象TeacherCreator部分的原型对象上设置一些方法,而不是其函数内。
  3. 我们在全局内存中定义一个teacher1常量。在执行上下文中执行函数之前我们不知道它的值。
  4. 在执行上下文中,首先要处理的还是函数参数。
  5. new关键字将为我们做的所有事情都以蓝色列出。
  6. 创建了包含给我们的函数的数据的对象。对象会在new关键字的帮助下自动this设置__proto__prototype对象。
  7. 现在,this返回的teacher1对象将是最终值,并且该执行上下文将被关闭。
  8. 这里调用我们创建的对象上的方法。JavaScript 将首先查找teacher1对象上的assignHomwork方法。它进入teacher1__proto__对象,但没有找到它,但 __proto__链接到prototype对象并在那里找到它并执行该函数。

ES6 class

class关键字语法的作用与前面方法中TeacherCreator构造函数的作用完全相同。然而,它给我们带来了编写更快代码的好处,并且看起来与其他语言中实现的 OOP 类似。

class TeacherCreator {
  constructor(name, profession, classes){
    this.name = name;
    this.profession = profession;
    this.clasess = clasess;
  }


  // methods that will be accessible in prototype later on:
  submitMark = function(mark: number, studentId: number) {
    //....
     console.log(`学生${studentId} 的分数是${mark}`)
  },

  assignHomework = function(homework: string, classId: number) {
    // ....
  }
}

ES6 类是否改变了迄今为止 OOP 的实现方式?

尽管我们的代码现在看起来更加清晰易读,但幕后的整个原理仍然是一样的。JavaScript 仍然会为我们的TeacherCreator类创建函数-对象组合。类内部的constructor方法与我们在构造函数方法中的组合中的函数相同。

总之,重复相同的过程,但变得更加自动化和干净。这是 JavaScript OOP 背后的一般过程,基本上是原型继承。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uboot中nfs和tftp方式获取文件

NFS文件系统挂载 服务器端配置如下 1.Server端需要安装NFS服务: sudo apt-get install nfs-kernel-server2.创建需要挂载的路径: mkdir -p /home/workspace/mercury/nfs_path3.创建共享目录: ①vim /etc/exports ②在文件中添加&#xff…

合并两个有序链表,剑指offer,力扣

目录 力扣题目地址: 原题题目: 我们直接看题解吧: 解题方法: 审题目事例提示: 解题思路: 具体流程如下: 代码实现: 知识补充: 力扣题目地址: 21. 合并两个有序…

git查看某个commit属于哪个分支方法(如何查看commit属于哪个分支)

有时候,当我们由于业务需求很多时,基于同一个分支新建的项目分支也会很多。 在某个时间节点,我们需要合并部分功能点时,我们会忘了这个分支是否已经合入哪个功能点,我们就会查看所有的commit记录,当我们找到…

2024-NeuDS-数据库题目集

一.判断题 1.在数据库中产生数据不一致的根本原因是冗余。T 解析:数据冗余是数据库中产生数据不一致的根本原因,因为当同一数据存储在多个位置时,如果其中一个位置的数据被修改,其他位置的数据就不一致了。因此,在数据…

GPIO HAL库+CubeMX

以正点原子精英版为例: 一.创建HAL库模块 二.GPIO输出 1.自己编写 void led_init(void) {GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOB_CLK_ENABLE();gpio_init_struct.Pin GPIO_PIN_5;gpio_init_struct.Mode GPIO_MODE_OUTPUT_PP;gpio_init_struct.Spee…

linux -系统通用命令查询

有时候内网环境下,系统有些命令没有安装因此掌握一些通用的linux 命令也可以帮助我们解决一些问题查看 1.查看系统内核版本 uname -r2.查看系统版本 cat /etc/os-release3. 查看cpu 配置 lscpu4.查看内存信息 free [参数] 中各个数值的解释如下表 数值解释t…

玻色量子“揭秘”之可满足性问题(SAT)与QUBO建模

​ 摘要:布尔可满足性问题(Boolean Satisfiability Problem,简称SAT问题)是逻辑学和计算机科学中的一个问题,它的目的是确定是否存在一种解释,使给定的布尔公式成立。换句话说,它询问给定布尔公…

OpenCV快速入门:图像分析——图像分割和图像修复

文章目录 前言一、图像分割1.1 漫水填充法1.1.1 漫水填充法原理1.1.2 漫水填充法实现步骤1.1.3 代码实现 1.2 分水岭法1.2.1 分水岭法原理1.2.2 分水岭法实现步骤1.2.3 代码实现 1.3 GrabCut法1.3.1 GrabCut法原理1.3.2 GrabCut法实现步骤1.3.3 代码实现 1.4 Mean-Shift法1.4.1…

面试题:为什么生产环境中,建议禁用 Redis 的 keys 命令?

keys命令的用法: keys pattern查找符合正则匹配的key的列表。扫描对象是Redis服务中所有的key,想想都很慢对不对? 同时执行keys命令的同时,Redis进程将被阻塞,无法执行其他命令,假如超过了哨兵的down-aft…

Android系统预装带so的apk

文章目录 前言配置新建Android.mk核心命令首次编译Apk已生成 但是无arm文件system.img 也已经更新 第一次刷入打开APP后闪退加入so文件如下为修改后的mk 第二次刷入mm报错查看手机系统abi路径下分别生成两个环境的so官方LOCAL_MULTILIB描述so打包错误验证so位数注释v7部分 第三…

界面组件DevExpress Reporting v23.1 - Web报表设计器功能升级

DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已经发布一段…

图解分库分表

中大型项目中,一旦遇到数据量比较大,小伙伴应该都知道就应该对数据进行拆分了。有垂直和水平两种。 垂直拆分比较简单,也就是本来一个数据库,数据量大之后,从业务角度进行拆分多个库。如下图,独立的拆分出…

【PyQt】(自定义类)阴影遮罩

写了一个感觉有些用的小玩具。 用于给控件添加阴影遮罩(强调主控件的同时屏蔽其余控件的点击) 自定义阴影遮罩Mask: from PyQt5.QtCore import QPoint,QRect,Qt,QPoint,QSize from PyQt5.QtWidgets import QWidget,QLabel,QPushButton,QVBoxLayout from PyQt5.QtGu…

Javaweb之前后台分离开发介绍的详细解析

2.1 前后台分离开发介绍 在之前的课程中,我们介绍过,前端开发有2种方式:前后台混合开发和前后台分离开发。 前后台混合开发,顾名思义就是前台后台代码混在一起开发,如下图所示: 这种开发模式有如下缺点&a…

视频剪辑技巧:如何高效批量转码MP4视频为MOV格式

在视频剪辑的过程中,经常会遇到将MP4视频转码为MOV格式的情况。这不仅可以更好地编辑视频,还可以提升视频的播放质量和兼容性。对于大量视频文件的转码操作,如何高效地完成批量转码呢?现在一起来看看云炫AI智剪如何智能转码&#…

基于STC12C5A60S2系列1T 8051单片读写掉电保存数据IIC总线器件24C02一字节并显示在液晶显示器LCD1602上应用

基于STC12C5A60S2系列1T 8051单片读写掉电保存数据IIC总线器件24C02一字节并显示在液晶显示器LCD1602上应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍IIC通信简单…

【Java从入门到大牛】网络编程

🔥 本文由 程序喵正在路上 原创,CSDN首发! 💖 系列专栏:Java从入门到大牛 🌠 首发时间:2023年11月23日 🦋 欢迎关注🖱点赞👍收藏🌟留言&#x1f4…

【LeetCode:2304. 网格中的最小路径代价 | dijkstra(迪杰斯特拉)】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

YOLOv8改进 | CARAFE既减少参数又提高精度的上采样方法

论文地址:官方论文地址点击即可跳转 代码地址:官方代码地址点击即可跳转 一、本文介绍 本文给大家带来的CARAFE(Content-Aware ReAssembly of FEatures)是一种用于增强卷积神经网络特征图的上采样方法。其主要旨在改进传统的上采…