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

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

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

相关文章

Python编写的爬虫为什么受欢迎?

每每回想起我当初学习python爬虫的经历,当初遇到的各种困难险阻至今都历历在目。即便当初道阻且长,穷且益坚,我也从来没有想过要放弃。今天我将以我个人经历,和大家聊一聊有关Python语音编写的爬虫的事情。谈一谈为什么最近几年py…

多线程,线程池,线程的创建,线程池的参数

文章目录 多线程-1 高并发〇、使用多线程的场景1. 为什么使用多线程 1. 线程概述1.1 线程和进程1.2 并发和并行1.3 多线程的优势1.4 程序运行原理1.5 主线程 1.6 线程的 6 种状态2. 线程的创建和启动2.1 Thread类2.2创建线程有哪几种方法2.2.1 继承**Thread**类,重写…

centos7 安装docker

1.卸载旧版本,不管装没装过,执行一下,防止版本冲突 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine 2. yum安装gcc相关 以及 安…

electron27-react-mateos:基于electron+react18仿matePad桌面系统

基于Electron27React18ArcoDesign搭建桌面版OS管理系统。 electron-react-mateos 基于最新前端跨端技术栈electron27.xreact18arco-designzustand4sortablejs构建的一款仿制matePad界面多层级路由管理OS系统。 ElectronReactOS支持桌面多路由配置,新开窗口弹窗开启路…

YB4051系列设备是高度集成的 Li-lon 和 Li-Pol 线性充电器,针对便携式应用的小容量电池。

YB4051H 300mA 单电池锂离子电池充电器0.1 mA 终端,45nA 电池漏电流 概述: YB4051系列设备是高度集成的 Li-lon 和 Li-Pol 线性充电器,针对便携式应用的小容量电池。它是一个完整的恒流/恒压线性充电器。不需要外部感应电阻,由于…

51单片机利用I/O口高阻状态实现触摸控制LED灯

51单片机利用I/O口高阻状态实现触摸控制LED灯 1.概述 这篇文章介绍使用I/O口的高阻状态实现一个触摸控制LED灯亮灭的实验。该实验通过手触摸P3.7引脚,改变电平信号控制灯的亮灭。 2.实验过程 2.1.实验材料 名称型号数量单片机STC12C20521LED彩灯无1晶振12MHZ1电…

Elasticsearch:ES|QL 函数及操作符

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

geemap学习笔记013:为遥感动态GIF图添加图名

前言 遥感动态GIF图可以展示地理区域随时间的变化,这对于监测自然灾害、湿地变化、城市扩展、农田变化等方面非常有用,并且可以反复观察图像,以更深入地了解地表的动态变化。本节主要是对遥感动态GIF图添加图名,以便于更好地理解…

聚观早报 |一加12正式开启预订;OPPO Reno11系列卖点

【聚观365】11月24日消息 一加12正式开启预订 OPPO Reno11系列卖点 小鹏第三季度营收财报 Claude 2.1 聊天机器人公布 现代汽车将与伦敦大学学院合作 一加12正式开启预订 全新的一加12系列公开亮相已有一段时间,不久前一加官方宣布,该机将于12月4日…

ebpf实战(一)-------监控udp延迟

问题背景: 为了分析udp数据通信中端到端的延迟,我们需要对整个通信链路的每个阶段进行监控,找出延迟最长的阶段. udp接收端有2个主要路径 1.数据包到达本机后,由软中断处理程序将数据包接收并放入udp socket的接收缓冲区 数据接收流程 2. 应用程序调用recvmsg等a…

<JavaEE> 什么是进程控制块(PCB Process Control Block)?

目录 一、进程控制块的概念 二、进程控制块的重要属性 2.1 唯一身份标识(PID) 2.2 内存指针 2.3 文件描述符表 2.4 状态 2.5 优先级 2.6 记账信息 2.7 上下文 一、进程控制块的概念 进程控制块(Process Control Block, PCB&#xff…

uni-app 跨端开发注意事项

文章目录 前言H5正常但App异常的可能性标题二H5正常但小程序异常的可能性小程序正常但App异常的可能性小程序或App正常,但H5异常的可能性App正常,小程序、H5异常的可能性使用 Vue.js 的注意区别于传统 web 开发的注意H5 开发注意微信小程序开发注意支付宝…

Docker实用篇

Docker实用篇 0.学习目标 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中,依赖的组件非常多,不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…

STM32入门笔记15_PWR电源管理模块

PWR和低功耗模式 PWR简介 PWR(Power Control) 电源控制PWR负责管理STM32内部的电源供电部分,可以实现可编程电压检测器和低功耗模式的功能可编程电压检测器(PVD) 可以监控VDD电源电压,当VDD下降到PVD阈值以下或上升到PVD阈值之上时,PVD会触…

C++学习之路(一)什么是C++?如何循序渐进的学习C++?【纯干货】

C是一种高级编程语言,是对C语言的扩展和增强。它在C语言的基础上添加了面向对象编程(OOP)的特性,使得开发者能够更加灵活和高效地编写代码。 C的名字中的“”符号表示在C语言的基础上向前发展一步,即“加加”&#x…

iOS APP包分析工具 | 京东云技术团队

介绍 分享一款用于分析iOSipa包的脚本工具,使用此工具可以自动扫描发现可修复的包体积问题,同时可以生成包体积数据用于查看。这块工具我们团队内部已经使用很长一段时间,希望可以帮助到更多的开发同学更加效率的优化包体积问题。 工具下载…

在VMware Workstation的Centos上实现KVM虚拟机的安装部署:详细安装部署过程(保姆级)

KVM概述 • 以色列qumranet公司研发,后被RedHad公司收购 (1)kvm只支持x86平台 (2)依赖于 HVM,inter VT AMD-v • KVM是(Kernel-based Virtual Machine)的简称,是一个开源的系统虚拟…

【Unity】 UGUI的PhysicsRaycaster (物理射线检测)组件的介绍及使用

1. 什么是PhysicsRaycaster组件? PhysicsRaycaster是Unity UGUI中的一个组件,用于在UI元素上进行物理射线检测。它可以检测鼠标或触摸事件是否发生在UI元素上,并将事件传递给相应的UI元素。 2. PhysicsRaycaster的工作原理 PhysicsRaycast…

【Proteus仿真】【51单片机】智能垃圾桶设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器,使用报警模块、LCD1602液晶模块、按键模块、人体红外传感器、HCSR04超声波、有害气体传感器、SG90舵机等。 主要功能: 系统运行后&#xf…

基于GPRS的汽车碰撞自动报警系统(论文+源码)

1. 系统设计 本次基于GPRS的汽车碰撞自动报警系统的设计中,其主要的目标功能如下:1、实时检测当前的GPS精度和纬度坐标;2.当发生碰撞后系统自动将当前的信息通过GPRS数据发送到远端数据进行报警;3、系统在碰撞后一方面进行本地报警…