实现isReactive和isReadonly

news2024/9/25 19:19:01

08_实现isReactive和isReadonly

一、实现isReactive

isReactive: 检查一个对象是否是由 reactive 创建的响应式代理。

1. 单元测试

// src/reactivity/tests/reactive.spec.ts

import { reactive, isReactive } from '../reactive';

describe('reactive', function () {it('happy path', function () {const original = { foo: 1 };const observed = reactive(original);expect(observed).not.toBe(original);expect(observed.foo).toBe(original.foo);// + isReactiveexpect(isReactive(observed)).toBe(true);expect(isReactive(original)).toBe(false);});
}); 

2. 代码实现

其实我们在baseHandlerscreateGetter的时候,我们就已经传递过isReadonly的标识,那我们只要想办法将这个标识传递出来,就可以了。

那就得触发代理对象的get操作,那先在reactive.ts中导出一个isReactive

// src/reactivity/reactive.ts

export function isReactive(value) {return value['is_reactive'];
} 

接着在get中判断读取的key是否是is_reactive,然后返回对应结果即可。

// src/reactivity/baseHandlers.ts

function createGetter(isReadonly = false) {return function get(target, key) {const res = Reflect.get(target, key);// + 如果读取的 key 是 is_reactive, 则返回 trueif (key === 'is_reactive') {return !isReadonly;}if (!isReadonly) {track(target, key);}return res;};
} 

至此,基本逻辑已经实现,看一下单测结果。

yarn test reactive 

果然失败了呢,通过报错信息我们可以看见期望Expectedfalse,而实际值Receivedundefined

其实也很容易明白🐴,普通对象没有被代理,自然不会走我们封装的get,而且也没有这个属性,所以就返回undefined

但是isReactive(observed)的测试是通过的,所以可知对代理过后的对象的判断是正确的,达到了期望。那只要想办法将undefined 转成false,且不影响isReactive(observed)返回的true即可。

两个思路:

  • 思路1:如果是true就正确返回,如果是undefined,就返回false。那就利用空值合并运算符??捕获undefinedreturn value['is_reactive'] ?? false; * 思路2:利用!!运算符,将表达式强转成布尔类型return !!value['is_reactive']; 其实能够看出来,思路1比起思路2不太优雅,所以我们选择思路2。

二、实现isReadonly

实现了isReactive之后,isReadonly就很类似了。

1. 单元测试

// src/reactivity/tests/readonly.spec.ts

it('happy path', () => {const original = { foo: 1, bar: { baz: 2 } };const wrapped = readonly(original);expect(wrapped).not.toBe(original);expect(wrapped.foo).toBe(1);// ! 不能被setwrapped.foo = 2;expect(wrapped.foo).toBe(1);// + isReadonlyexpect(isReadonly(wrapped)).toBe(true);expect(isReadonly(original)).toBe(false);
}); 

2. 代码实现

同上,即可。

// src/reactivity/reactive.ts

export function isReadonly(value) {return !!value['is_readonly'];
} 
// src/reactivity/baseHandlers.ts

function createGetter(isReadonly = false) {return function get(target, key) {const res = Reflect.get(target, key);if (key === 'is_reactive') {return !isReadonly;} else if (key === 'is_readonly') { // + is_readonlyreturn isReadonly;}if (!isReadonly) {track(target, key);}return res;};
} 

走一下readonly的单测。

# --silent=true 是禁用控制台打印,静默测试,主要是因为之前的set会触发console.warn
yarn test readonly --silent=true 

三、代码重构

export function isReactive(value) {return !!value['is_reactive'];
}

export function isReadonly(value) {return !!value['is_readonly'];
} 

这里就是一个优化的点,就像报错信息一样,报错可以用字典来维护起来,这里也是一样,可以用tsenum枚举来维护。

// src/reactivity/reactive.ts

export const enum ReactiveFlags {IS_REACTIVE = '__v_isReactive',IS_READONLY = '__v_isReadonly'
}

// + 用到之前标识的地方,相应的进行修改
export function isReactive(value) {return !!value[ReactiveFlags.IS_REACTIVE];
}

export function isReadonly(value) {return !!value[ReactiveFlags.IS_READONLY];
} 
// src/reactivity/baseHandlers.ts

import { track, trigger } from './effect';
import { ReactiveFlags } from './reactive';

function createGetter(isReadonly = false) {return function get(target, key) {const res = Reflect.get(target, key);// + 改成枚举的方式if (key === ReactiveFlags.IS_REACTIVE) {return !isReadonly;} else if (key === ReactiveFlags.IS_READONLY) {return isReadonly;}if (!isReadonly) {track(target, key);}return res;};
} 

大概就这么多,重构完以后,依旧完整的跑一遍所有的单测。

# --watchAll可以进入watch模式, 下面有很多 usage 可供使用
# 这样做的好处是, 我们不需要每次都执行 yarn test, 在第一次执行之后, 进程会自动监听测试用例的变化, 如果测试用例代码发生了变化, 会自动执行
yarn test --watchAll --silent=true 

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

Callable接口

前言 获取多线程的方法,我们都知道有三种,还有一种是实现Callable接口 实现Runnable接口实现Callable接口实例化Thread类使用线程池获取Callable接口 Callable接口,是一种让线程执行完成后,能够返回结果的 在说到Callable接口…

【Unity天空盒】卡通渲染中如何实现云的消散效果

写在前面 完成大气渲染之后,接下来就是考虑云渲染了。因为我想做的天空盒本身是想跟着这位大佬Unity 卡通渲染 程序化天空盒 - 知乎里叙述的进程来的,里面云实现的是原神里的云,原神又是在崩3的基础上加上了消散效果。但现在能找到的一些教程…

线程中的sleep, yield, join

1. 前言 今天以具体实例的方法来详细记录下实战中的sleep, yield, join。 到底是什么意思,应该怎么用呢??? 2. 适合人群 对该类方法的概念比较模糊的人 3. 开始 3.1 sleep 此方法是一个静态方法,可以通过类名直接调…

【MyBatis】安装 + 框架搭建 + 使用 + 优化(全程一条龙服务讲解~)

目录 前言 一、准备工作 1.1、下载MyBatis 1.2、数据库设计 二、搭建框架 2.1、创建Maven项目 2.2、jar包、引入依赖 2.3、创建MyBatis核心配置文件 2.4、映射文件 2.5、通过junit测试功能 2.6、框架优化 三、小结——注意事项 前言 本篇全程从0到1搭建MyBatis框架…

Python编程 简单春节倒计时教程(附源代码)

作者简介:一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.应用的技术 1.Tkinter 2.PHotoimage 函数 3.label组件 二.效果图 三…

pytorch 咖啡豆识别

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍦 参考文章地址: 365天深度学习训练营-第P6周:好莱坞明星识别🍖 作者:K同学啊一、前期准备 1.设置GPU import torch from torch import nn …

2022 年 pnpm 为什么这么火?

pnpm是 Node.js 的替代包管理器。它是 npm 的直接替代品,但速度更快、效率更高。 为什么更有效率?当你安装一个包时,我们将它保存在你电脑上的全局存储中,然后我们从它创建一个硬链接而不是复制。也就是说:对于模块的…

8.移动端学习-rem适配方案

1.适配方案 1、当设备尺寸发生变化时,页面宽高等比例变化 2、使用媒体查询根据不同设备按比例设置html字体大小,页面元素使用rem做单位,当html字体大小变化,元素尺寸也会发生变化,从而达到等比缩放的适配 2.rem实际开…

ubuntu18.04运行ORB_SLAM2

1、基础工具安装 安装cmake、git、gcc、g。 sudo apt-get install cmake git gcc g 2、安装Eigen库 在终端输入以下代码。 sudo apt-get install libeigen3-dev 3、安装Pangolin0.5 版本过高会导致错误,安装依赖项。 sudo apt-get install libglew-dev libpyth…

Hadoop之Hdfs

一、基本概述 1、定义 HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目 录树来定位文件;其次,它是分布式的。HDFS 的使用场景:适合一次写入&#xff0…

这是长新冠,还是我老了?浙江出国抢订单又抢CTO;脉脉发布人才迁徙报告;元宇宙产业生态图谱;GitHub今日热榜 | ShowMeAI资讯日报

👀日报合辑 | 🎡AI应用与工具大全 | 🔔公众号资料下载 | 🍩韩信子 🎡 这是长新冠,还是我老了? 感染后身体出现了疲劳、关节疼痛、咳嗽等新症状?你并不孤单!约翰霍普金斯…

数据结构进阶 二叉树OJ题一

作者:小萌新 专栏:数据结构进阶 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:介绍几道二叉树的oj题 二叉树OJ题题目一 根据二叉树创建字符串题目二 二叉树的层序遍历题目三 二叉树的最近公共祖先题目一 根据…

自动化信息治理:推动价值、安全性和合规性

现代组织充斥着数据,但信息的洪流可能变得势不可挡,危及利用其价值的能力。内容服务解决方案能够减轻洪水泛滥的风险,并帮助组织更好地控制信息。 从信息中获取价值的不同之处在于治理。建立正确的治理框架,组织可以最大限度地利…

难以挖掘的真相——塑料版薯条、意大利面、披萨……

下方图片中的“美食”,看起来是不是十分美味? ▲莱佛士平面设计学生作品 可千万要擦亮眼睛,它们其实是:黄色瓶盖“蛋黄”的荷包蛋,黄色吸管的“薯条”,桔黄色的塑料带子“意大利面”,红色塑料袋…

Exynos4412的Linux5.4.174时钟驱动开发(四)——clk API的调用方法

系列文章目录 Exynos4412的Linux时钟驱动开发(一)——Exynos4412的时钟管理单元CMU Exynos4412的Linux时钟驱动开发(二)——clock的初始化(CLK_OF_DECLARE的机制) Exynos4412的Linux时钟驱动开发&#x…

新蜂商城 -- 代码学习研读

新蜂商城 -- 代码学习研读1.Big Data -- Postgres1.1 Big Data -- Postgres2.Big Data -- Postgres3.AwakeningGit Website: https://github.com/newbee-ltd/newbee-mall. 新蜂商城线上预览地址: http://mall.newbee.ltd. 👉👉学习的朋友给个小星星.感…

蓝牙标签操作流程

电脑网页端后台系统 下载蓝牙标签APP注册账号,登录电脑网页端即可制作模板 蓝牙标签管理系统 安卓手机系统 1. 使用手机浏览器扫码下载 2. 拷贝链接到手机浏览器下载 http://a.picksmart.cn:8088/picksmart/app/new-app-release-v3.0.31.apk 苹果手机系统&#…

公众号运营要做什么?公众号运营规划方案分享

你真的理解什么是公众号运营吗? 公众号运营遵循的是创作-分发-增长-变现的路径,从内容创作到内容分发到用户增长,到最终的转化变现,这才是完整的一个运营闭环,在这条路径中,缺少了哪一环都将影响整体运营效…

学习笔记之范海鹰微表情识别

微表情识别1. 微表情由来1.1 基本情绪和次级情绪1.2 保罗埃克罗的贡献2. 微表情意义2.1 微表情产生原理2.2 微表情的形态意义2.3 微表情的读心内涵2.4 微表情的应用价值3.微表情面部表情3.1 基线反应3.2 惊讶3.3 厌恶、轻蔑3.4 愤怒3.5 恐惧3.6 悲伤3.7 愉悦作为网上冲浪12级选…

redis实现session管理以及缓存穿透与雪崩

小伙正在评博客之星,欢迎大家来互相助力 我的链接 redis实现session管理以及缓存穿透与雪崩一、Redis实现分布式Session管理1 管理机制2 开发Session管理1. 引入依赖2. 开发Session管理配置类3.打包测试即可二、缓存穿透与雪崩缓存穿透缓存击穿(量太大&a…