JavaScript进阶----《getter 和 setter 是什么》

前言: 这两个属性在学习前端的时候看到过,但是由于项目中没有用到过,所以一直没有细致的了解。今天 review 同事代码的时候,遇到了这个写法,看了半天也不知道如何处理。再不学习真的以后连别人的代码都不知道什么意思了。而后经过查阅 MDN 以后,颠覆了自己对 js 的基础知识 —“对象(object)” 的认知,并由此深感自己的不足。故今天来做一个简单总结,讲给同样在学习路上的你。

tips: 如果你是 react 开发,你可以选择直接跳跃至标题二开始阅读。如果你是 vue 开发,我强烈建议你从标题一开始阅读,你会更加有代入感的阅读本文。

因为作者主要是 vue 开发,本文的由来就是阅读同事的 vue 代码有感而作,但是也请 react 开发的同学不要害怕,没有标题一也并不会影响你阅读本文的整体感受🎁。

一. 初次相遇的场景

  1. 第一次遇到这两个名词的场景,是在学习 Vue3 教程的过程中,在看到 computed 的用法时,看到了下面这样一段描述:
    image.png
    原文链接:vue3 Computed 讲解

  2. 回顾一下我们在 vue3computed 常用的写法。我在项目中最常用的方法就是给 computed 传递一个回调函数, 这个回调函数返回值就是这个计算属性的值。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqFfVsVK-1688007173495)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/af7ff16637e04a37baaeeb0e63bbf7ec~tplv-k3u1fbpfcp-watermark.image?)]

  3. 随着写的项目越来越多,我逐渐形成了一个惯性思维,好像 computed 就是这样“仅此而已”。其实不然,它还有更进阶的用法,接下来让我们继续慢慢理解。

  4. 相信大家一定理解下面的代码为什么会报错。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-guD65dmV-1688007173495)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/79a9cbbd98494f77ada817b91c8f2d6f~tplv-k3u1fbpfcp-watermark.image?)]

  5. 因为我们上面是 computed 的基础用法,这样用其实你只给这个 name 这个属性设置了 getter。这样就导致了你这个 name 属性只能读取,而不能改写(或者叫做重新赋值)
    image.png

  6. 听到这里,你可能和最开始的我一样困惑。什么 getter? 我连单词 get 都没看见,你就在这里自言自语 getter,别急,一步一个脚印慢慢来。

  7. 仔细看我们上面的写法,我们如果只给 computed 函数一个函数作为参数。如下图:
    image.png
    那么其实上面的写法等价于下面的写法(tips:暂时忽略报错,这里的报错不是重点
    image.png

  8. 你可能更加好奇了,什么鬼,从哪里凭空冒出来一个 get? 为啥这样写就不能重新赋值了?在此之前你必须更加深入了解 object 这个类型。

二. object 属性的定义方法

  1. 这里我准备了一个空对象,现在我想让你给这个 obj 赋予一个叫做 name 的属性。值为字符串类型的 “韩振方”。你会怎么做?
    image.png

  2. 我觉得你甚至不需要思考,条件反射的都可以写出下面的代码。
    image.png

  3. 你要知道,其实这一步你是在完成一个对 obj属性描述过程

  4. 让我们完整的回顾上面的过程:你刚刚给 obj 这个对象添加了一个属性叫做 ‘name’,并且这个 name值(value) 是一个叫做 “韩振方” 的字符串。

  5. 接下来我将告诉你的是,在你 obj.name=“韩振方”的时候,你其实间接的调用了 Object 原型身上的 defineProperty 方法。

三. Object.defineProperty

  1. MDN 上查阅可知,这个函数有三个参数。
    image.png

  2. 让我换一种方法,重新写 obj.name=“韩振方” 这段代码,那么它其实等价于Object.defineProperty(obj,"name",{value:"韩振方",...})
    注意! 上面的代码不严谨,它省略了一部分内容。我只是想通过上面引出我们接下来要讲解十分重要的知识点属性描述符。 后面我会慢慢补充省略的内容。

  3. 由上面代码我们可以知道这个函数的基本用法,接收3个参数,第一个参数是要添加属性的对象(obj),第二个参数是要添加的属性名称(name),关键点是第三个属性,这个属性是一个对象类型的参数。我们的重点是搞清楚这第三个参数都有什么选项。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hSJhbWcW-1688007173497)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5c519fb5cfd24a80a09a0ab5af1366ee~tplv-k3u1fbpfcp-watermark.image?)]

  4. 由于篇幅限制,在本文中,我们暂时忽略“enumerable”和“configurable”这两个属性。我们重点看下面这几个属性。
    image.png

  5. 在讲解下面的知识之前,我想再强调一下,第三个参数属性描述符 是一个对象类型,{}它有且只有一些固定的键值对。它用来约束这个即将要定义的属性的一些行为。

四. value 和 writable

  1. value,我相信这个选项非常非常容易理解,就是你给这个属性即将赋予的值。

  2. 读懂了下面带红线的句子,你应该就明白了一个没有赋值的属性是为什么值是 undefined 的了吧?
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S06U9Aog-1688007173497)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/728e5e5c14974d90a42184912ec44cfe~tplv-k3u1fbpfcp-watermark.image?)]

    image.png

  3. writable 是否可写,这里可写说白了就是是否可以重新被赋值。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9FPaavn-1688007173497)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5cc9beaa57e9480db0879b27df5d26eb~tplv-k3u1fbpfcp-watermark.image?)]

  4. 强调一下这里 writbale 默认值不是我们想象中的 true 而是 false

  5. 回顾我们上面的代码。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PX4rSwS7-1688007173497)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/25909a2ff5094ba184b6eab34e917f2f~tplv-k3u1fbpfcp-watermark.image?)]
    由于我们没有定义 writable ,所以按道理来讲它是不可重新赋值的。 让我们验证一下:
    不出所料,控制台报错了,并且报错信息和猜测的一样,不能给只读属性赋值。
    image.png

  6. 让我们设置 writabletrue 再重新尝试一下。
    image.png
    可以看到控制台的错误没有了,并且正确输出了修改过后的值。
    image.png

  7. 别忘了,刚刚我们重新赋值的代码,obj.name="小韩" 这一步本质上还是在重复使用 Object.defineProperty 这个函数。正好也对应了 MDN 的这段解释。
    image.png

五. getter 和 setter

  1. 标题的内容终于到了,其实 gettersetter 并没有那么难理解。

  2. 首先让我们搞明白一个过程。下面的代码是在控制台输出 objname 属性的值。对吧?
    image.png

  3. 其实你的这个动作 obj.(注意有个点)obj点 的过程是在“读取obj 对象的 name 属性。注意这个 “读取” 的动作。这个读取其实就是对应了获取 value 的过程。
    image.png

  4. 这个动作正好就是 getter 要做的行为。首先别看叫 getter 就很害怕,它其实就是属性描述符的一个属性 get 而已,仅此而已。只不过这个属性的值是一个函数。起了个外国人名字,加了个 er 叫起来顺口而已。

  5. 什么?有点绕?还不懂?一个普通对象,有一个属性,属性值是一个函数。像下面,一个对象 hanzhenfang ,有一个属性叫做 skill,值是一个函数,能够被执行,执行后在控制台输出一个哈哈
    image.png
    怎么我这样写你就能明白,换个说法就不明白了呢?

  6. 回到 getter,我想你可能马上想到 getter 的用法应该像下面这样。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NnLAeyUT-1688007173498)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b48facfa1c704020888f8622e31d95fc~tplv-k3u1fbpfcp-watermark.image?)]
    对不起,这样是不允许的,因为 get 属性的返回值将会被作为属性值的读取结果给你。这样会造成编译器无法知道你的像 obj.name 这样的属性值读取过程该返回给你哪一个值。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BtZvFggW-1688007173498)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/590b410b05d2440a95f0387fde9dd7e3~tplv-k3u1fbpfcp-watermark.image?)]

  7. 你只把 value 去掉也是不可以的,因为 writable 对应我们马上要讲的 setter
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZXYnpbHO-1688007173498)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c8b55c315c014a3abb4ce8a48eb678b7~tplv-k3u1fbpfcp-watermark.image?)]
    image.png

  8. 所以正确的 gettr 用法是下面这样。
    image.png
    image.png

  9. 让我们不设置 setter,尝试把 name 修改回 韩振方 试一下。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xhbSbM0I-1688007173499)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d831f02ba384432b1b93e63e2c4aaeb~tplv-k3u1fbpfcp-watermark.image?)]
    有了上面的 writable 的经验,我们大概率要翻车。果然控制台报错了,“你不能给一个只有 getter 的对象属性重新赋值。”
    image.png

  10. 聪明的你一定想到了下面的结论,没错, getter 对应的是 value ,而setter 对应的正是 writable

  11. setter 也是一个值为函数的属性,不过这个属性接收一个参数,这个参数正是赋值运算符右边的内容。(也就是等号右边的值)千万一定要仔细看我们下面的写法。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pq37cNnv-1688007173499)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2b9d7bea116542aa8d17486fb0442e46~tplv-k3u1fbpfcp-watermark.image?)]

  12. 我们仅仅在 setter 函数的内部打印了一下新的值,而并没有对新的值做任何操作,那么其实我们 objname 属性仍为数字 10
    image.png
    验证一下:
    image.png

  13. 为什么要这样做呢?我举个简单的例子,这样会给我们一个十分重要的中间处理步骤。假设我在给 obj 重新命名。因为我姓,你改的名字里姓氏最起码得是才可以通过吧?你直接改成吴彦祖那不乱拉套了?
    image.png
    可以看到我们可以在 setter 正确拦截错误的操作。
    image.png

  14. 请原谅我啰嗦一大堆,因为我想如果像上面这样用实际例子演示可能会比 MDN 这样一段大白话更加通俗易懂。
    image.png

六. 重新分析 computed

回过头再看我们标题一的问题就显得十分清晰了。
image.png
image.png

七. 思考题

gettersetter 有一个经典的错误使用案例。请分析为什么下面的代码会引起递归导致栈溢出?
image.png
控制台输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-njikwhbo-1688007173500)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6a3df9c48472420f89285f0d62b6c302~tplv-k3u1fbpfcp-watermark.image?)]
image.png
如果你明白了上面代码报错的原因,我想你也就明白了 gettersetter 🎁。

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

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

相关文章

spring Cloud使用Skywalking搭建笔记

skywalking支持dubbo,SpringCloud,SpringBoot集成,代码无侵入,通信方式采用GRPC,性能较好,实现方式是java探针,支持告警,支持JVM监控,支持全局调用统计等等,功…

uniapp 中 引入vant组件 和 vant 报错Unclosed bracket 的问题解决

在uniapp 中引入vant组件,遇到一个报错,所以在此记录一下完整过程 一、引入vant组件 方式一:前往 GitHub官网 Vant 下载压缩文件,获取下载中的dist 文件 方式二:通过npm install 方式引入 npm i vant/weapp -S --pr…

Android Studio 找不到 uploadArchives 入口

在4.2之前版本的 Android Studio 中想要module 打包arr,上传Maven 我们只需要 在对应module的build.gradle文件顶部添加 apply plugin: maven然后每一次修改记得要修改版本号,相同版本号提交失败,是不会覆盖的 defaultConfig {......versi…

2022年12月份青少年软件编程Python等级考试试卷六级真题(含答案)

一、单选题(共25题,共50分) 1.数据文件“abc.txt”中包含若干个英文单词,如图所示: 读取文件“abc.txt”中数据的Python程序段如下: file abc.txt word_b [] for word in open(file):if word[0:1] a and len(word)>4:wo…

工具系列之wireshark使用说明

简介 工具下载: https://www.wireshark.org/官方FAQ: https://www.wireshark.org/faq.html 过滤器设置 通常情况下,将.pcap 数据拖拽至 wireshark中即可打开。通过: 导航栏–》分析 --> 显示过滤器 即可找到对应的筛选器,筛…

优维低代码实践:数据加工/转化详解

优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大运维人提供一个技术交流与学习的平台。 优维…

自然语言处理(概念)

1、 RNN模型简介 1.2传统RNN模型 2、LSTM模型 3、GRU模型 5、注意力机制 6、人名分类器 7 、BERT 8、Transformer 的结构是什么样子的? 各个子模块有什么作用? 8.1 Encoder模块 8.2 Decoder模块 8.3 Transformer 结构中的Decoder端具体输入是什么&#…

期末复习【网络安全】

期末复习【网络安全】 前言推荐期末复习重点第1章 引言1.1 计算机安全概念 21.2 OSI安全体系结构 61.3 安全攻击 71.3.1 被动攻击1.3.2 主动攻击 第2章 对称加密和消息机密性2.1 对称加密原理 232.1.3 Feistel密码结构 25 2.2 对称分组加密算法 272.2.1 数据加密标准2.2.2 三重…

【强化学习】常用算法之一 “Q-learning”

作者主页:爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

如何看待低级爬虫与高级爬虫?

爬虫之所以分为高级和低级,主要是基于其功能、复杂性和灵活性的差异。根据我总结大概有下面几点原因: 功能和复杂性:高级爬虫通常提供更多功能和扩展性,包括处理复杂页面结构、模拟用户操作、解析和清洗数据等。它们解决了开发者…

Spring基础知识(四)

目录 1.Spring包含的模块主要有什么 2.Core Container的作用 3.Data Access/Integration模块的作用 4.AOP模块的作用 5.Spring Web模块的作用 6.Test模块的作用 7.如何将一个类声明为Bean 8.Component和Bean的区别 9.能够注入Bean的注解有什么 10.Resource注解 1.Spr…

《微服务实战》 第三十二章 微服务链路跟踪-sleuth zipkin

系列文章目录 第三十二章 微服务链路跟踪-sleuth zipkin 第三十章 分布式事务框架seata TCC模式 第二十九章 分布式事务框架seata AT模式 第十二章 Spring Cloud Alibaba Sentinel 第十一章 Spring Cloud Alibaba nacos配置中心 第十章 SpringCloud Alibaba 之 Nacos discover…

APP外包开发中的第三方工具

APP外包开发过程中需要用到各种的第三方服务平台和工具,这些平台和工具可以提高开发效率和更规范的管理项目,今天和大家分享常见的一些平台和工具,从UI设计、开发、测试到上线覆盖APP开发的整个流程,希望对大家有所帮助。北京木奇…

Solr框架 02.Solr操作(document操作和query查询)

菜单项目Documents使用办法 其中的document选项&#xff1a; 以XML格式举例 1新增/修改 当id不存在时新增&#xff0c;当id存在修改。 <doc> <field name"id">8</field> <field name"name">明天更大卖</field> <field n…

CVE-2023-34541 LangChain 任意命令执行

漏洞简介 LangChain是一个用于开发由语言模型驱动的应用程序的框架。 在LangChain受影响版本中&#xff0c;由于load_prompt函数加载提示文件时未对加载内容进行安全过滤&#xff0c;攻击者可通过构造包含恶意命令的提示文件&#xff0c;诱导用户加载该文件&#xff0c;即可造成…

Spring Boot 中的 @SendTo 注解

Spring Boot 中的 SendTo 注解 在 Spring Boot 中&#xff0c;SendTo 注解是一个非常有用的注解&#xff0c;它可以用于实现 WebSocket 的消息转发功能。本文将介绍 SendTo 注解的原理、使用方法和示例代码。 什么是 SendTo 注解 SendTo 注解是 Spring Boot 中用于将消息发送…

【MOOC 测验】第4章 网络层

1‌、下列关于路由算法描述错误的是&#xff08; &#xff09; A. 链路状态算法是一种全局路由算法&#xff0c;每个路由器需要维护全局状态信息B. OSPF 是一种域内路由协议&#xff0c;核心是基于 Dijkstra 最低费用路径算法C. RIP 是一种域内路由算法&#xff0c;核心是基…

docker网络

一、docker网络概述 1、docker网络实现的原理 Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c;Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c; 同时Docker网桥是 每个容器的…

基于ENVI的遥感影像的非监督分类

ENVI包括了ISODATA和K-Mean两种非监督分类方法。 ISODATA&#xff08;Iterative Self-Orgnizing Data Analysize Technique&#xff09;是一种重复自组织数据分析技术&#xff0c;计算数据空间中均匀分布的类均值&#xff0c;然后用最小距离技术将剩余像元进行迭代聚合&#x…

Unreal 5 实现使用GPU Instancing批量渲染相同的物体

之前做unity的时候&#xff0c;专门研究了使用GPU进行批量相同的物体渲染&#xff0c;现在转ue以后&#xff0c;发现UE也有相同的功能。接下来讲解一下&#xff0c;在ue里面如何实现通过GPU进行实例化渲染。 创建组件 能够实现GPU实例化渲染&#xff0c;ue提供了两个组件&…