JS中的OOP

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 背后的一般过程,基本上是原型继承。

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

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

相关文章

补充:如何提高selenium的运行速度?

已经通读该专栏文章的同学,或许对UI自动化测试有了一定的掌握,细心的同学肯定会发现一个问题,当用例量达到一定程度时,对于整体用例的执行速度肯定不会很满意。除了应用多线程运行用例的方式加快速度,有没有其他的方法呢? 今天告诉大家,方法是有的!也是本人新学的。即…

C#串口通信从入门到精通(27)——高速通信下解决数据处理慢的问题(20ms以内)

前言 我们在开发串口通信程序时,有时候会遇到比如单片机或者传感器发送的数据速度特别快,比如10ms、20ms发送一次,并且每次发送的数据量还比较大,如果按照常规的写法,我们会发现接收的数据还没处理完,新的数据又发送过来了,这就会导致处理数据滞后,软件始终处理的不是…

Django中间件与csrf

一. django中间件 1. 什么是django中间件 # django中间件是django的门户1. 请求来的时候需要先经过中间件才能到达真正的django后端2. 响应走的时候最后也需要经过中间件才能发送出去 2. django中间件的个数 django自带七个中间件, 分别是SecurityMiddleware, SessionMiddle…

WordPress站点屏蔽过滤垃圾评论教程(Akismet反垃圾评论插件)

前段时间我的WordPress站点经常收到垃圾评论的轰炸,严重时一天会收到几十条垃圾评论。我这个小破站一没啥流量,二又不盈利,实在是不太理解为啥有人要这么执着地浪费资源在上面。 Akismet反垃圾评论插件 其实用了 Akismet 反垃圾评论插件后&a…

Python BDD 框架比较之 pytest-bdd vs behave

pytest-bdd和behave是 Python 的两个流行的 BDD 测试框架,两者都可以用来编写用户故事和可执行的测试用例, 具体选择哪一个则需要根据实际的项目状况来看。 先简单看一下两者的功能: pytest-bdd 基于pytest测试框架,可以与pytest…

PCIE链路训练-状态机描述2

Configuration.Lanenum.Accept 如果use_modified_TS1_TS2_Ordered_Set为1,需要注意: (1)tx需要发送Modified TS1而不是正常的TS1; (2)rx端必须检查是否收到Modified TS1(注意一开…

STM32_6(TIM)

TIM定时器(第一部分) TIM(Timer)定时器定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时不仅…

测试Bard和ChatGPT对双休有关法规的认知和简单推理

Bard是试验品,chatgpt是3.5版的。 首先带着问题,借助网络搜索,从政府官方网站等权威网站进行确认,已知正确答案的情况下,再来印证两个大语言模型的优劣。 想要了解的问题是,在中国,跟法定工作…

通过Whisper模型将YouTube播放列表中的视频转换成高质量文字稿的项目

项目简介 一个通过Whisper模型将YouTube播放列表中的视频转换成高质量文字稿的项目。 这个基于 Python 的工具旨在将 YouTube 视频和播放列表转录为文本。它集成了多种技术,例如用于转录的 Fast-Whisper、用于自然语言处理的 SpaCy 以及用于 GPU 加速的 CUDA&…

使用Pytorch从零开始构建LSTM

长短期记忆(LSTM)网络已被广泛用于解决各种顺序任务。让我们了解这些网络如何工作以及如何实施它们。 就像我们一样,循环神经网络(RNN)也可能很健忘。这种与短期记忆的斗争导致 RNN 在大多数任务中失去有效性。不过&a…

解决mv3版本浏览器插件,不能注入js脚本问题

文章目录 背景引入ifream解决ifream和父页面完全跨域问题参考链接 背景 浏览器插件升级mv3版本后,不能再使用content_script内容脚本向原浏览器(top)注入script标签达到注入脚本的目的。浏览器认为插入未经审核的脚本是不安全的行为。 引入…

经常喝羊奶,羊大师告诉你会有何不同

经常喝羊奶,羊大师告诉你会有何不同 羊奶,与人们日常饮用的牛奶相比,一直都没有得到足够的关注。然而,羊奶在一些特定方面却具有独特的优势。它不仅具有丰富的营养价值,还有助于提升人体的健康水平。本文小编羊大师将…

【Skynet 入门实战练习】游戏模块划分 | 基础功能模块 | timer 定时器模块 | logger 日志服务模块

文章目录 游戏模块基础功能模块定时器模块日志模块通用模块 游戏模块 游戏从逻辑方面可以分为下面几个模块: 注册和登录网络协议数据库玩法逻辑其他通用模块 除了逻辑划分,还有几个重要的工具类模块: Excel 配置导表工具GM 指令测试机器人…

【CCF-PTA】第03届Scratch第01题 -- 梦醒时分

梦醒时分 【题目描述】 睡眠是人体正常的生理需要,同年龄男女睡眠时间无明显差别,一般是8小时左右。居家的小明作息生活很规律,晚上11点睡觉,早晨7点起床学习。请你编写程序来判断,每周(共168小时&#x…

Elasticsearch:ES|QL 函数及操作符

如果你对 ES|QL 还不是很熟悉的话,请阅读之前的文章 “Elasticsearch:ES|QL 查询语言简介​​​​​​​”。ES|QL 提供了一整套用于处理数据的函数和运算符。 功能分为以下几类: 目录 ES|QL 聚合函数 AVG COUNT COUNT_DISTINCT 计数为近…

【计算机网络笔记】数据链路层概述

系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…

IAR为恩智浦S32M2提供全面支持,提升电机控制能力

IAR Embedded Workbench for Arm已全面支持恩智浦最新的S32系列,可加速软件定义汽车的车身和舒适性应用的开发 瑞典乌普萨拉,2023年11月22日 – 嵌入式开发软件和服务的全球领导者IAR现已全面支持恩智浦半导体(NXP Semiconductors&#xff0…

好工具|datamap,一个好用的地图可视化Excel插件,在Excel中实现地理编码、拾取坐标

在做VRP相关研究的时候,需要对地图数据做很多处理,比如地理编码,根据“重庆市沙坪坝区沙正街174号”这样的一个文本地址知道他的经纬度;再比如绘制一些散点图,根据某个位置的经纬度在地图上把它标注出来。还有有的时候…

Redis-Redis高可用集群之水平扩展

Redis3.0以后的版本虽然有了集群功能,提供了比之前版本的哨兵模式更高的性能与可用性,但是集群的水平扩展却比较麻烦,今天就来带大家看看redis高可用集群如何做水平扩展,原始集群(见下图)由6个节点组成,6个节点分布在三…

一致性 Hash 算法 Hash 环发生偏移怎么解决

本篇是对文章《一文彻底读懂一致性哈希算法》的重写,图文并茂,篇幅较长,欢迎阅读完提供宝贵的建议,一起提升文章质量。如果感觉不错不要忘记点赞、关注、转发哦。原文链接: 《一文彻底读懂一致性Hash 算法》 通过阅读本…