10_实现readonly
在某些时候,我们希望定义一些数据是只读的,不允许被修改,从而实现对数据的保护,即为 readonly
只读本质上也是对数据对象的代理,我们同样可以基于之前实现的 createReactiveObject 函数来实现,可以为此函数添加第三个参数 isReadonly,如下:
function createReactiveObject(value, isShallow = false, isReadonly = false){}
而有了这个参数之后,我们还需要对拦截器进行其他操作,修改或者删除一个对象的属性,都是改变此对象,因此我们需要针对这两个进行拦截,如下:
const noWarnKey = [RAW_KEY, IS_REACTIVE, ITERATE_KEY]// set
function baseSet(isReadonly) {return function set(target, key, newVal, receiver) {// isReadonly 为 true 时,禁止修改,而一些内部属性则忽略if (isReadonly && !noWarnKey.includes(key)) {// 并弹出警告console.warn('只读属性 ', key, ' 禁止修改')return true}const oldVal = target[key]const type = Object.prototype.hasOwnProperty.call(target, key) ? TrggerType.SET : TrggerType.ADDconst result = Reflect.set(target, key, newVal, receiver)if (!result) returnif (receiver[RAW_KEY] === target) {if (!Object.is(oldVal, newVal)) {trigger(target, key, type)}}return result}
}// delete
function baseDeleteProperty(isReadonly) {return function deleteProperty(target, key) {if (isReadonly && !noWarnKey.includes(key)) {console.warn('只读属性 ', key, ' 禁止删除')return true}const hadKey = Object.prototype.hasOwnProperty.call(target, key)const result = Reflect.deleteProperty(target, key)if (hadKey && result) {trigger(target, key, TrggerType.DELETE)}return result}
}// get
function baseGet(isShallow, isReadonly) {return function get(target, key, receiver) {if (key === RAW_KEY) {return target}// 只有当前的对象是一个非只读数据时,才需要收集依赖if (!isReadonly) {track(target, key)}const result = Reflect.get(target, key, receiver)if (isShallow) return resultif (typeof result === 'object' && result !== null) {return reactive(result)}return result}
}function createReactiveObject(value, isShallow = false) {if (typeof value !== 'object' || value === null) {console.warn('value 必须是一个对象')return value}if (reactiveMap.has(value)) {return reactiveMap.get(value)}if (isReactive(value)) return valueconst proxy = new Proxy(value, {get: baseGet(isShallow),set: baseSet(isReadonly),has,ownKeys,deleteProperty: baseDeleteProperty(isReadonly)})proxy[IS_REACTIVE] = truereactiveMap.set(value, proxy)return proxy
}function readonly(value) {return createReactiveObject(value, false, true)
}
现在我们写一段代码进行一下测试:
const obj = { a: 1 }
const r1 = readonly(obj)
r1.a++console.log(r1)
结果如图:

不过目前还存在一个问题,目前的只读只能处理成浅响应,案例如下:
const obj = {a: 1,b: {c: 3}
}
const r1 = readonly(obj)
r1.b.c++console.log(r1)
测试结果如图:

我们虽然在创建 readonly 函数时,给 createReactiveObject 的第二个参数是 false,表示是深响应的,但从结果可以看到,没有被拦截,而且依然被修改了。
所以按照之前的经验,如果要深处理,就直接进行递归处理即可,所以我们可以进行如下修改:
function baseGet(isShallow, isReadonly) {return function get(target, key, receiver) {if (key === RAW_KEY) {return target}// 只有当前的对象是一个非只读数据时,才需要收集依赖if (!isReadonly) {track(target, key)}const result = Reflect.get(target, key, receiver)if (isShallow) return result// 在此处进行递归处理if (typeof result === 'object' && result !== null) {// 若开启了只读,则使用 readonly 函数包装结果,实现递归处理每一层return isReadonly ? readonly(result) : reactive(result)}return result}
}
我们在使用之前的测试案例,执行 r1.b.c++ ,来查看一下结果,如图:

而如果要实现浅响应,那就更加简单了,如下:
function shallowReadonly(value) {// 只需要将 isShallow 设置为 true 即可,表示只处理第一层// - 设置 isShallow 为 true 后,在 get 中,就会直接返回这个属性的原有的值,不做代理、只读或者其他处理return createReactiveObject(value, true, true)
}
相关文章:
10_实现readonly
在某些时候,我们希望定义一些数据是只读的,不允许被修改,从而实现对数据的保护,即为 readonly 只读本质上也是对数据对象的代理,我们同样可以基于之前实现的 createReactiveObject 函数来实现,可以为此函数…...
简单介绍$listeners
$listeners 它可以获取父组件传递过来的所有自定义函数,如下: // 父组件 <template><div class"a"><Child abab"handleAbab" acac"handleAcac"/></div> </template><script> impor…...
架构设计笔记-20-补充知识
知识产权 我国没有专门针对知识产权制定统一的法律(知识产权法),而是在民法通则规定的原则下,根据知识产权的不同类型制定了不同的单项法律及法规,如著作权法、商标法、专利法、计算机软件保护条例等,这些法律、法规共同构成了我…...
scrapy 爬虫学习之【中医药材】爬虫
本项目纯学习使用。 1 scrapy 代码 爬取逻辑非常简单,根据url来处理翻页,然后获取到详情页面的链接,再去爬取详情页面的内容即可,最终数据落地到excel中。 经测试,总计获取 11299条中医药材数据。 import pandas as…...
PDH稳频技术粗谈
PDH(Plesiochronous Digital Hierarchy)是一种传输技术,主要用于数字通信中的传输系统。PDH稳频技术是指在PDH传输系统中,通过稳定频率来实现传输系统的稳定性和可靠性。 PDH传输系统中,时钟同步是非常重要的。传输系…...
[LeetCode] 130. 被围绕的区域
题目描述: 给你一个 m x n 的矩阵 board ,由若干字符 X 和 O 组成,捕获 所有 被围绕的区域: 连接:一个单元格与水平或垂直方向上相邻的单元格连接。区域:连接所有 O 的单元格来形成一个区域。围绕&#x…...
C语言位运算
目录 1.C语言位运算符表 2.C语言移位运算符详解(配实例作业) 3.C语言&按位与运算符详解 4.C语言|按位或运算符详解 5.C语言^按位异或运算符详解 6.C语言~取反运算符详解 C语言位运算这一章主要介绍C语言位运算符表、C语言移位运算符、C语言&按…...
Go 语言中格式化动词
当然,我很乐意为你提供 Go 语言中所有的格式化动词的完整列表。Go 语言的格式化动词非常丰富,可以满足各种打印和格式化需求。以下是完整的列表: 通用: %v - 以默认格式打印值 %v - 类似 %v,但对结构体会添加字段名 %#…...
CSS3 动画相关属性实例大全(四)(font、height、left、letter-spacing、line-height 属性)
CSS3 动画相关属性实例大全(四) (font、height、left、letter-spacing、line-height 属性) 本文目录: 一、font 属性(所有字体属性) 1.1、font-size属性(指定字体的大小) 1.2、f…...
大模型涌现判定
什么是大模型? 大模型:是“规模足够大,训练足够充分,出现了涌现”的深度学习系统; 大模型技术的革命性:延申了人的器官的功能,带来了生产效率量级提升,展现了AGI的可行路径&#x…...
LeetCode 1456.定长子串中元音的最大数目
题目: 给你字符串 s 和整数 k 。 请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。 英文中的 元音字母 为(a, e, i, o, u)。 思路:定长滑动窗口 入 更新 出 代码: class Solution {pub…...
freeswitch-esl 三方设备实现监听功能
使用场景: A和B在通话中,C想监听A和B通话内容 方法一: 修改拨号计划<extension name="global" continue="true"><condition><action application="info"/>...
【LeetCode】123.买卖股票的最佳时间
清晰明了的思路是解决问题的至上法宝。如何把一个复杂的问题拆成简单的问题,就是我们需要考虑的。 1. 题目 2. 思想 这道题虽然是难题,但是思想比较简单。 题目要求说至多买卖两次,也就是说,也可以买卖一次,这种情况…...
elk部署安装
elk部署 前提准备1、elasticsearch2、kibana3、logstash 前提准备 1、提前装好docker docker-compose相关命令 2、替换docker仓库地址国内镜像源 cd /etc/docker vi daemon.json # 替换内容 {"registry-mirrors": [ "https://docker.1panel.dev", "ht…...
使用 JAX 进行 LLM 分布式监督微调
LLM distributed supervised fine-tuning with JAX — ROCm Blogs (amd.com) 24年1月25日,Douglas Jia 发布在AMD ROCm 博客上的文章。 在这篇文章中,我们回顾了使用 JAX 对基于双向编码器表示(BERT)的大型语言模型(LL…...
【简单版】通过 Window.performance 实现前端页面(性能)监控
1 背景 前端监控系统告警xx接口fetchError 问题:前端监控系统没有更多的错误信息,查询该fetch请求对应的接口日志返回200状态码、无请求异常记录,且后台能查到通过该fetch请求成功发送的数据。那是前端页面的错误还是前端监控系统的问题&…...
微信小程序考试系统(lw+演示+源码+运行)
摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了微信小程序考试系统的开发全过程。通过分析微信小程序考试系统管理的不足,创建了一个计算机管理微信小程序考试系统的方案。文章介绍了微信小程序考…...
手机摄影入门
感觉会摄影的人是能够从生活中发现美的人。 我不太会拍照,觉得拍好的照片比较浪费时间,而且缺乏审美也缺乏技巧,所以拍照的时候总是拍不好。但有时候还是需要拍一些好看的照片的。 心态和审美可能需要比较长时间提升,但一些基础…...
微信小程序手机号授权获取(aes加密手机号)
<view class="container"> <view class=topTabSwiper> <view class=tab {{currentData == 0 ? "tabBorer" : ""}} data-current = "0" bindtap=checkCurrent>一键授权<span class="tab_bor"><…...
asyn queueRequest使用实例
使用queueRequest读写端口驱动的示例,驱动驱动程序使用一个基于asyn实现了asynCommon和asynOctet的驱动程序-CSDN博客中编写的驱动程序,本程序的C代码如下: #include <stdlib.h> #include <stdio.h> #include <string.h>#…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
