Vue3.js“非原始值”响应式实现基本原理笔记(四)浅响应和深响应、只读和浅只读

如果您觉得这篇文章有帮助的话!给个点赞和评论支持下吧,感谢~

作者:前端小王hs

阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主

此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来

书籍:《Vue.js设计与实现》 作者:霍春阳

本篇博文将在书第5.1节5.4节的基础上进一步总结所提到的基础概念,附加了测试的代码运行示例,方便正在学习Vue3想分析Vue3源码的朋友快速阅读

如有帮助,不胜荣幸

前文:
Vue3.js“非原始值”响应式实现基本原理笔记(一)
Vue3.js“非原始值”响应式实现基本原理笔记(二)
Vue3.js“非原始值”响应式实现基本原理笔记(三)

浅响应与深响应

假设传入一个嵌套着对象的对象

  • 浅响应:只有表层对象具有响应式
  • 深响应:递归地将对象的所有嵌套属性都转换为响应式的

在Vue3.js“非原始值”响应式实现基本原理笔记(三)中第一次出现了reactive,其实就是对proxy对象的一个封装函数,现在来看一下这样做出现的问题以及继续完善的方法

其实读到这里,可以发现书的走向就是不断的提出问题并完善响应式的一个过程,对于响应式的问题,就是不能触发副作用函数

我们先来看如何实现深响应

来看书中的代码:

const obj = reactive({  foo: {  bar: 1  }  
});  effect(() => {  console.log(obj.foo.bar);  
});  obj.foo.bar = 2; // 修改值不会触发响应

来看一下effect()中的执行流程:

  1. 因为不是lazy,直接执行effectFn,进而执行匿名函数
  2. 读取obj.foo,调用trackobj.fooeffectFn进行关联
  3. 执行return Reflect.get(target, key, receiver)返回{bar:1}

所以整个过程bareffect不会有关系,那么也就不会触发响应了

如果需要深响应,只需将返回的{bar:1}再丢进reactive里即可,这里就需要做一个判断,Reflect.get返回的得是一个对象且不为null,最终代码如下:

function reactive(obj) {return new Proxy(obj, {get(target, key, receiver) {if (key === 'raw') {return target;}track(target, key);const res = Reflect.get(target, key, receiver);if (typeof res === 'object' && res !== null) {return reactive(res);}return res;}// 省略其他拦截函数});  
}

这样,深响应就实现了


但是有时候我们不需要所有的嵌套对象都实现响应,那么就催生了浅响应,也就是shallowReactive,shallow是浅的意思

实现的过程也非常简单,只需添加一个形参,用于告知函数是否需要进行深响应,反之则浅响应,代码如下:

// 默认为 false,即非浅响应  
function createReactive(obj, isShallow = false) {return new Proxy(obj, {get(target, key, receiver) {if (key === 'raw') {return target;}const res = Reflect.get(target, key, receiver);if (isShallow) {return res;}track(target, key);  if (typeof res === 'object' && res !== null) {  return reactive(res);}return res;}// 省略其他拦截函数});
}

最后,在createReactive外套上reactiveshallowReactive,就是我们在文档中看到的API了:

function reactive(obj) {return createReactive(obj);
}function shallowReactive(obj) {return createReactive(obj, true);
}

只读和浅只读

只读的逻辑与浅响应相同,都是在新增形参在函数中进行判定,逻辑非常简单,代码如下:

// 增加第三个参数 isReadonly,代表是否只读,默认为 false,即非只读
function createReactive(obj, isShallow = false, isReadonly = false) {return new Proxy(obj, {// 拦截设置操作set(target, key, newVal, receiver) {// 如果是只读的,则打印警告信息并返回if (isReadonly) {console.warn(`属性 ${key} 是只读的`);return true;}// 省略其他return res;},deleteProperty(target, key) {// 如果是只读的,则打印警告信息并返回  if (isReadonly) {  console.warn(`属性 ${key} 是只读的`);  return true;  }  // 省略其他return res;  }  // 省略其他拦截函数  });
}

可以看到,如果是只读的,也就是isReadonlytrue,那么不管是修改还是删除,都会弹出警告

同理,由于是只读的,所以只读的对象也没有必要触发effect,代码如下:

get(target, key, receiver) {if (!isReadonly) {track(target, key)}
// 省略其他
}

readonly如下所示:

function readonly(obj) {  return createReactive(obj, false, true /* 只读 */);  
}

当然,现在只是浅只读,如果是const obj = readonly({ foo: { bar: 1 } }),在读取obj.foo.bar时仍然可以修改

因为Reflect.get(target, key, receiver)返回的对象又执行了reactive(res),所以还需进行一个判定,就是如果为只读,就进行再次调用readonly,而不是调用reactive,代码如下:

if (typeof res === 'object' && res !== null) {  // 如果数据为只读,则调用 readonly 对值进行包装  return isReadonly ? readonly(res) : reactive(res);  
}

最后,在createReactive外套上readonlyshallowReadonly,就是我们在文档中看到的API了:

function readonly(obj) {return createReactive(obj, false, true);
}function shallowReadonly(obj) {return createReactive(obj, true, true);
}

总结

  1. 如何实现深响应和浅响应
  2. 如何实现只读和浅只读

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

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

相关文章

为什么大学讲授 C 语言比讲授 C++ 的更多?

大学更倾向于讲授C语言而不是C的几个原因可能包括。我收集归类了一份嵌入式学习包,对于新手而言简直不要太棒,里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕设800套和语言类教学,敲个22就可以免费获得。 基础性质:…

【Pytorch实战教程】对抗样本生成中是如何添加噪声的?

文章目录 对抗样本中添加随机生成的对抗噪声代码解析应用场景示例代码对抗样本中添加随机生成的对抗噪声 通常在对抗训练或者生成对抗样本时使用,目的是为了稍微扰动模型的输入数据,从而测试或增强模型在面对输入数据轻微变化时的鲁棒性。 x = x + torch.zeros_like(x).uni…

CPTAC蛋白数据库的补充(自备)

目录 关于CPTAC数据库 资料下载 数据分析 相关网站说明:Proteomic Data Commons (cancer.gov) 关于CPTAC数据库 两个基因相关性CPTAC蛋白组数据_cptac分析蛋白表达相关性-CSDN博客 两个基因相关性细胞系(CCLE)(升级)-CSDN博客 CPTAC数据门户是一个集中的存储库,用…

【Linux】进程程序替换 + 模拟实现简易shell

前言 上一节我们介绍了 **进程终止**和 **进程等待**等一系列问题,并做了相应的验证,本章将继续对进程控制进行介绍,重点学习进程程序替换,并进行相应验证,在此基础上,自己模拟实现一个shell,该…

Redis分布式锁-Redisson可重入锁原理的个人见解。

记录Redisson可重入锁的个人见解。 文章目录 前言一、什么叫做锁的重入?二、Redisson可重入锁原理 前言 ⁣⁣⁣⁣ ⁣⁣⁣⁣ 之前在写项目的时候,注意到Redisson可重入锁的一个问题,随即在网上搜索其对应的资料,下面就记录一下个…

软件开发面试题C#,.NET知识点(续)

1.C#中的封装是什么,以及它的重要性。 封装(Encapsulation) 是面向对象编程(OOP)的一个基本概念。它指的是将对象的状态(属性)和行为(方法)绑定在一起,并且将…

昇思25天学习打卡营第14天 | ShuffleNet图像分类

昇思25天学习打卡营第14天 | ShuffleNet图像分类 文章目录 昇思25天学习打卡营第14天 | ShuffleNet图像分类ShuffleNetPointwise Group ConvolutionChannel ShuffleShuffleNet模块网络构建 模型训练与评估数据集训练模型评估模型预测 总结打卡 ShuffleNet ShuffleNetV1是旷世科…

鸿蒙实训笔记

第一天 #初始化一个新的NPM项目(根据提示操作) npm init #安装TSC、TSLint和NodeJS的类型声明 npm install -s typescript tslint types/node 在根目录中新建一个名为tsconfig.json的文件,然后在代码编辑器中打开,写入下述内容: {"co…

租用海外服务器需要考虑哪些因素

当企业选择租用海外服务器时需要考虑到哪些因素呢? 对于海外服务器的租用我们需要考虑到机房的位置以及服务器的稳定性如何,所以企业可以选择离目标用户群体比较近一点的机房,以此来降低服务器的延迟度并且能够提高用户的访问速度。 对于机房…

MATLAB激光通信和-积消息传递算法(Python图形模型算法)模拟调制

🎯要点 🎯概率论和图论数学形式和图结构 | 🎯数学形式、图结构和代码验证贝叶斯分类器算法:🖊多类型:朴素贝叶斯,求和朴素贝叶斯、高斯朴素贝叶斯、树增强贝叶斯、贝叶斯网络增强贝叶斯和半朴素…

网络层重点协议—IP协议

在复杂的网络环境中确定一个合适的路径 协议头格式如下: 4位版本号(version) 指定协议的版本(IPV4-4,IPV6-6) 4位首部长度(header length) IP头部的长度是多少个32bit,也就是length*4的字节数。4bit表示最大的数字是15&#x…

大模型日报 2024-07-14

大模型日报 2024-07-14 大模型资讯 ⏩6700 万参数比肩万亿巨兽 GPT-4!微软 MIT 等联手破解 Transformer 推理密码 微软、MIT 等机构的学者提出创新训练范式,攻破大模型推理缺陷。通过因果模型构建数据集,教模型学习公理,67M 参数的…

【密码学】密码学数学基础:群的定义

一、群的定义 在密码学中,群(Group)的概念是从抽象代数借用来的,它是一种数学结构,通常用于描述具有特定性质的运算集合。 群的定义 群定义中的几个关键要素: 集合:首先,群是由一系…

PyMuPDF 包读取pdf文档时,span里的flags属性代表什么

在 PyMuPDF(也称为 fitz)库中,flags 属性表示文本的格式化信息。flags 是一个整数,它包含了不同位(bits)的标志,每个位代表文本的一种属性。这些标志位可以组合在一起表示复杂的文本格式。 具体…

AutoMQ 中的元数据管理

本文所述 AutoMQ 的元数据管理机制均基于 AutoMQ Release 1.1.0 版本 [1]。 01 前言 AutoMQ 作为新一代基于云原生理念重新设计的 Apache Kafka 发行版,其底层存储从传统的本地磁盘替换成了以对象存储为主的共享存储服务。对象存储为 AutoMQ 带来可观成本优势的…

draggable 实现一个简单的拖拽

拖拽区域代码 <draggable v-if="activeFirstIndex !== 8" :list="showResourseList" :group="{ name: resources, pull: clone, put: false }" :sort="false" :multiple="false" :move="onMove1" @end="…

qt 让一个控件可见和不可见

在Qt中&#xff0c;要让一个控件&#xff08;如按钮、文本框等&#xff09;可见或不可见&#xff0c;可以使用QWidget类的setVisible()方法。setVisible()方法接受一个布尔值参数&#xff0c;true表示控件可见&#xff0c;false表示控件不可见。 以下是一个简单的示例&#xf…

android studio 怎么下载 buildTool

在Android Studio中下载Build Tools&#xff0c;通常可以通过Android Studio内置的SDK Manager来完成。以下是详细的步骤&#xff1a; 一、通过Android Studio的SDK Manager下载Build Tools 启动Android Studio&#xff1a;首先&#xff0c;确保你已经安装了Android Studio&am…

Java编程基础入门——构建你的第一个Java程序

Java&#xff0c;作为一门广泛使用的编程语言&#xff0c;以其“一次编写&#xff0c;到处运行”的特性而闻名于世。无论是开发企业级应用、Android移动应用&#xff0c;还是进行大数据处理&#xff0c;Java都扮演着举足轻重的角色。对于初学者而言&#xff0c;掌握Java编程基础…

【JavaScript 算法】冒泡排序:简单有效的排序方法

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 冒泡排序&#xff08;Bubble Sort&#xff09;是一种基础的排序算法&#xff0c;通过重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它…