【个人笔记js的原型理解】

在 JavaScript 中,最常见的新建一个对象的方式就是使用花括号的方式。然后使用’ . '的方式往里面添加属性和方法。可见以下代码:

let animal = {};
animal.name = 'Leo';
animal.energe = 10;animal.eat = function (amount) {console.log(`${this.name} is eating.`)this.energe += amount
}animal.sleep = function (length) {console.log(`${this.name} is sleeping.`)this.energe += length
}animal.play = function (length) {console.log(`${this.name} is playing.`)this.energe -= length
}

但通常的应用场景下,你会需要生成多种动物。这则需要把以上的逻辑抽象成一个函数。可见以下代码,生成了 leo 和 snoop 两个动物。

function Animal(name, energy){let animal = {};animal.name = name;animal.energy = energy;animal.eat = function (amount) {console.log(`${this.name} is eating.`)this.energy += amount}animal.sleep = function (length) {console.log(`${this.name} is sleeping.`)this.energy += length}animal.play = function (length) {console.log(`${this.name} is playing.`)this.energy -= length}return animal;
}const leo = Animal('Leo', 7);
const snoop = Animal('Snoop', 10)

但是按照上面代码,每次新创建一个animal,就需要把里面的eat、sleep、play方法都会被重新创建一遍。

因为eat、sleep、play方法都很相似,所以我们可以把他们放在一个animalMethods里面,这样只需要在内存里面创建一次。然后每次我们需要创建一个新动物,我们只是指向了animalMethods里面的方法,而不是重新创造这些方法。

const animalMethods = {eat(amount) {console.log(`${this.name} is eating.`)this.energy += amount},sleep(length) {console.log(`${this.name} is sleeping.`)this.energy += length},play(length) {console.log(`${this.name} is playing.`)this.energy -= length}
}
function Animal(name, energy){let animal = {};animal.name = name;animal.energy = energy;animal.eat = animalMethods.eat;animal.sleep = animalMethods.sleep;animal.play = animalMethods.play;return animal;
}

以上代码中,比如animal增加一个方法poop,就需要到Animal函数 里面增加 animal.poop = animalMethods.poop 。 如果想要Animal总能指向 animalMethods里面的任何一个方法,可以使用Object.create()传入animalMethods,使得在Animal里面找不到对应属性或方法时,就会去animalMethods查找,并调用对应方法。

const animalMethods = {eat(amount) {console.log(`${this.name} is eating.`)this.energy += amount},sleep(length) {console.log(`${this.name} is sleeping.`)this.energy += length},play(length) {console.log(`${this.name} is playing.`)this.energy -= length}
}
function Animal(name, energy) {let animal = Object.create(animalMethods)animal.name = name;animal.energy = energy;return animal;
}
const leo = Animal('Leo', 7);
console.log(leo.play(7)) //Leo is playing.

以上的用法就是JavaScript 原型(prototype)的由来。

那么什么原型?它就是函数上的一个属性,指向一个对象。

既然原型是每个函数都有的属性,那么与其单独管理 animalMethods ,为什么我们不把 animalMethods 放到函数的原型上呢?

function Animal(name, energy) {let animal = Object.create(Animal.prototype)animal.name = name;animal.energy = energy;return animal;
}Animal.prototype.eat = function (amount) {console.log(`${this.name} is eating.`)this.energy += amount
}
Animal.prototype.sleep = function (length) {console.log(`${this.name} is sleeping.`)this.energy += length
}
Animal.prototype.play = function (length) {console.log(`${this.name} is playing.`)this.energy -= length
}const leo = Animal('Leo', 7);
console.log(leo.eat(5)) //Leo is eating.

以上代码告诉了我们三点:

如何创建一个构造函数(构造函数就是构造一个对象)
如何将方法添加到构造函数的原型上(eg:Animal.prototype.eat()={…})
如何使用Object.create()指向函数原型。
这三点的目的就是为了构造函数的所有实例都能共享实例上的方法。

接下来会引入关键词 new 来对上面代码再进行进一步优化。使用new关键词,js会自动做Object.create()和return的动作,并且需要使用this对象来替换原本的animal对象。

function Animal(name, energy) {// let this = Object.create(Animal.prototype) //这一步的作用:1、创建对象 2、指向Animal.prototypethis.name = name;this.energy = energy;// return this; //输出创建的对象
}Animal.prototype.eat = function (amount) {console.log(`${this.name} is eating.`)this.energy += amount
}
Animal.prototype.sleep = function (length) {console.log(`${this.name} is sleeping.`)this.energy += length
}
Animal.prototype.play = function (length) {console.log(`${this.name} is playing.`)this.energy -= length
}const leo = new Animal('Leo', 7);
const snoop = new Animal('Snoop', 10)
console.log(leo.sleep(15)) //Leo is sleeping.

以上这些操作,就是基本上创建了一个class。在es6,JavaScript有了class关键词。接下来就用class来重构以上的代码。

class Animal {constructor(name, energy) {this.name = namethis.energy = energy}eat(amount) {console.log(`${this.name} is eating.`)this.energy += amount}sleep(length) {console.log(`${this.name} is sleeping.`)this.energy += length}play(length) {console.log(`${this.name} is playing.`)this.energy -= length}
}const leo = new Animal('Leo', 7);
const snoop = new Animal('Snoop', 10)
console.log(leo) //Animal { name: 'Leo', energy: 7 }
console.log(leo.sleep(1)) //Leo is sleeping.

既然可以用js建造class,那么为什么还需要花这么多时间了解上面的prototype,this,new?原因是class是function的语法糖,提供了更便捷的方式创建对象。class最终会被编译为function,其中的方法会成为prototype上面的共享方法。

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

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

相关文章

大学物理 之 安培环路定理

文章目录 前言什么是安培环路定理安培环路定理有什么作用 深入了解深入学习 前言 什么是安培环路定理 安培环路定理的物理意义在于描述了电流和磁场之间的相互作用,以及如何在一个封闭的回路中分析这种相互作用。 简单的来说 , 用环路定理来解决在磁场中B对任意封…

[管理与领导-65]:IT基层管理者 - 辅助技能 - 4- 职业发展规划 - 乌卡时代(VUCA )

前言: 大多数IT人,很勤奋,但都没有职业规划,被工作驱动着前行,然而,作为管理者,你就不能没有职业规划思维,因为你代表一个团队,你的思维决定了一个团队的思维。本文探讨…

redis实战-实现优惠券秒杀解决超卖问题

全局唯一ID 唯一ID的必要性 每个店铺都可以发布优惠券: 当用户抢购时,就会生成订单并保存到tb_voucher_order这张表中,而订单表如果使用数据库自增ID就存在一些问题: id的规律性太明显,容易被用户根据id的间隔来猜测…

c++ 学习之 构造函数的使用

上代码 class person { public:person(){cout << " person 的无参默认构造函数 " << endl;}person(int age){cout << " person 的有参默认构造函数 " << endl;m_age age;}person(const person& other){cout << "…

如何实现的手机实景自动直播,都有哪些功能呢?

手机实景自动直播最近真的太火了&#xff0c;全程只需要一部手机&#xff0c;就能完成24小时直播带货&#xff0c;不需要真人出镜&#xff0c;不需要场地&#xff0c;不需要搭建直播间&#xff0c;只需要一部手机就可以了。真人语音讲解&#xff0c;真人智能回复&#xff0c;实…

MySQL用户管理及用户权限

目录 数据库用户管理 新建用户 查看用户 重命名用户rename 删除用户drop 修改用户密码 找回root密码 数据库用户授权 授予权限 查看用户权限 撤销用户权限 数据库用户管理 新建用户 CREATE USER 用户名来源地址 [IDENTIFIED BY [PASSWORD] 密码];用户名&#xff1a…

C#-单例模式

文章目录 单例模式的概述为什么会有单例模式如何创建单例模式1、首先要保证&#xff0c;该对象 有且仅有一个2、其次&#xff0c;需要让外部能够获取到这个对象 示例通过 属性 获取单例 单例模式的概述 总结来说&#xff1a; 单例 就是只有 一个实例对象。 模式 说的是设计模式…

《Go 语言第一课》课程学习笔记(十二)

函数 Go 函数与函数声明 在 Go 语言中&#xff0c;函数是唯一一种基于特定输入&#xff0c;实现特定任务并可返回任务执行结果的代码块&#xff08;Go 语言中的方法本质上也是函数&#xff09;。在 Go 中&#xff0c;我们定义一个函数的最常用方式就是使用函数声明。 第一部…

Mybatis学习|注解开发、lombok

1.使用注解开发 无需再编写相应的Mapper.xml文件&#xff0c;直接将sql用注解的形式写在Mapper接口的对应方法上即可。 然后因为没有xml文件,所以要在mybatis-config.xml核心配置文件中注册这个Mapper接口&#xff0c;而不用去注册之前的Mapper.xml&#xff0c;这里其实如果用…

QT listWidget 中实现元素的自由拖拽

QListWIdget中拖拽元素移动 setMovement(QListView::Movement::Free);setDragEnabled(true); setDragDropMode(DragDropMode::DragDrop); setDefaultDropAction(Qt::DropAction::MoveAction);

nginx-反向代理缓存

反向代理缓存相当于自动化动静分离。 将上游服务器的资源缓存到nginx本地&#xff0c;当下次再有相同的资源请求时&#xff0c;直接讲nginx缓存的资源返回给客户端。 本地缓存资源有一个过期时间&#xff0c;当超过过期时间&#xff0c;则重新向上游服务器重新请求获取资源。…

SIEM(安全信息和事件管理)解决方案

什么是SIEM 安全信息和事件管理&#xff08;SIEM&#xff09;是一种可帮助组织在安全威胁危害到业务运营之前检测、分析和响应安全威胁的解决方案&#xff0c;将安全信息管理 (SIM) 和安全事件管理 (SEM) 结合到一个安全管理系统中。SIEM 技术从广泛来源收集事件日志数据&…

Matlab——二维绘图(最为详细,附上相关实例)

为了帮助各位同学备战数学建模和学习Matlab的使用&#xff0c;今天我们来聊一聊 Matlab 中的绘图技巧吧&#xff01;对于 Matlab 这样的科学计算软件来说&#xff0c;绘图是非常重要的一项功能。在数据处理和分析时&#xff0c;良好的绘图技巧能够更直观地呈现数据&#xff0c;…

【DP】CF Edu 21 E

Problem - E - Codeforces 题意&#xff1a; 思路&#xff1a; 就是一个 N为1e5&#xff0c;M为3e5的背包问题&#xff0c;不过特殊条件是 w < 3 我们去从最简单的情况开始考虑 当只有w 1的物品和w 2的物品时&#xff0c;考虑贪心地把物品按价值排序&#xff0c;然后选…

Docker部署项目

相关系列文章&#xff1a; 1、DockerHarbor私有仓库快速搭建 2、DockerJenkinsHarbor 3、Docker安装Mysql、Redis、nginx、nacos等环境 1、jenkins构建前端并上传服务器 在这篇文章中(DockerJenkinsHarbor)未完成前端的远程部署&#xff0c;这里对前端vue工程进行编译打包并上…

虚拟内存相关笔记

虚拟内存是计算机系统内存管理的一个功能&#xff0c;它允许程序认为它们有比实际物理内存更多的可用内存。它使用硬盘来模拟额外的RAM。当物理内存不足时&#xff0c;操作系统将利用磁盘空间作为虚拟内存来存储数据。这种机制提高了资源的利用率并允许更大、更复杂的应用程序的…

BLDC无感方波控制

BLDC无感控制 反电动势过零检测反电动势检测方法比较器模式采样过零信号闭环的建立 BLDC 方波启动技术转子预定位电机的外同步加速电机运行状态的转换 程序部分 反电动势过零检测 它的主要核心就是通过检测定子绕组的反电动势过零点来判断转子当前的位置。 三相六状态 120通电…

IDEA 报 Cannot resolve symbol ‘HttpServletResponse‘ 解决

springboot2版本换成springboot3之后&#xff0c;代码这里突然报红了&#xff0c; 首先要淡定&#xff0c;把原先Import的引入删掉&#xff0c;重新引入试试呢&#xff0c;是不是很简单哈哈。 原来&#xff0c;springboot3的路径是&#xff1a; import jakarta.servlet.http…

4.2 实现基于栈的表达式求值计算器(难度4/10)

本作业主要考察&#xff1a;解释器模式的实现思想/栈结构在表达式求值方面的绝对优势 C数据结构与算法夯实基础作业列表 通过栈的应用&#xff0c;理解特定领域设计的关键作用&#xff0c;给大家眼前一亮的感觉。深刻理解计算机语言和人类语言完美结合的杰作。是作业中的上等…

Docker进阶:mysql 主从复制、redis集群3主3从【扩缩容案例】

Docker进阶&#xff1a;mysql 主从复制、redis集群3主3从【扩缩容案例】 一、Docker常规软件安装1.1 docker 安装 tomcat&#xff08;默认最新版&#xff09;1.2 docker 指定安装 tomcat8.01.3 docker 安装 mysql 5.7&#xff08;数据卷配置&#xff09;1.4 演示--删除mysql容器…