当前位置: 首页 > news >正文

【Vue3 源码解析】reactive 全家桶

// 泛型约束:只能传入引用类型
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
// 判断只读,否则创建reactive响应式对象
export function reactive(target: object) {// if trying to observe a readonly proxy, return the readonly version.if (isReadonly(target)) {return target}return createReactiveObject(target,false,mutableHandlers,mutableCollectionHandlers,reactiveMap)
}

这段代码是 Vue 3 中的 reactive 函数的实现部分,它用于将一个对象转化为深度响应式代理对象。下面是这段代码的详细解释:

  1. 函数签名:

    • function reactive<T extends object>(target: T): UnwrapNestedRefs<T>:这是 reactive 函数的类型签名,它接受一个泛型参数 T,表示目标对象的类型,并返回一个与目标对象类型相同的深度响应式代理对象。UnwrapNestedRefs<T> 类型用于解包嵌套的 Ref,以获得原始值。

    • function reactive(target: object):这是 reactive 函数的实际实现。

  2. 实现逻辑:

    • 首先,函数检查目标对象 target 是否已经被标记为只读(readonly)。如果是只读的,就直接返回目标对象本身,因为只读对象不应该被转化为响应式对象。

    • 如果目标对象不是只读的,那么就调用 createReactiveObject 函数来创建深度响应式代理对象。这里传递了一些参数:

      • target:要代理的目标对象。
      • false:表示不是只读的,即要创建可修改的代理对象。
      • mutableHandlers:处理深度响应式代理对象属性变化的处理器集合。
      • mutableCollectionHandlers:处理集合类型属性变化的处理器集合。
      • reactiveMap:WeakMap,用于存储对象和它们的响应式代理之间的映射关系。
  3. 总结:

    • 这段代码实现了 reactive 函数的核心逻辑,它负责创建一个深度响应式代理对象,该对象能够追踪目标对象属性的变化,并在变化时通知相关视图进行更新。如果目标对象已经是只读对象,那么函数不会再对其进行代理,而是直接返回只读对象本身。
function createReactiveObject(target: Target,isReadonly: boolean,baseHandlers: ProxyHandler<any>,collectionHandlers: ProxyHandler<any>,proxyMap: WeakMap<Target, any>//WeakMap的 键 只能是一个object类型的数据,并且WeakMap的键名所指向的对象,不计入垃圾回收机制//它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。//因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。//也就是说,一旦不再需要,WeakMap里面的键名对象和所对应的键值对会自动消失,不用手动删除引用
) {// 如果传入的是普通的基本数据类型if (!isObject(target)) {if (__DEV__) {console.warn(`value cannot be made reactive: ${String(target)}`)}return target}// target is already a Proxy, return it.// exception: calling readonly() on a reactive object// target 已经被代理过,并且不是为了将响应式对象变为只读,则直接返回if (target[ReactiveFlags.RAW] &&!(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {return target}// target already has corresponding Proxy// 从缓存(readonlyMap,reactiveMap)中查找,如果已经被代理过则直接返回const existingProxy = proxyMap.get(target)if (existingProxy) {return existingProxy}// only specific value types can be observed.// 如果在白名单直接返回 例如 __skip__const targetType = getTargetType(target)if (targetType === TargetType.INVALID) {return target}// 如果以上条件都没触发,则会进行一个proxy代理const proxy = new Proxy(target,targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers)// 缓存新代理后的对象proxyMap.set(target, proxy)return proxy
}

这段代码是 Vue 3 中用于创建响应式代理对象的核心逻辑,它实现了 createReactiveObject 函数。下面是这段代码的详细解释:

  1. 函数签名:

    • function createReactiveObject(target: Target, isReadonly: boolean, baseHandlers: ProxyHandler<any>, collectionHandlers: ProxyHandler<any>, proxyMap: WeakMap<Target, any>):这是 createReactiveObject 函数的类型签名。它接受以下参数:
      • target:要代理的目标对象。
      • isReadonly:一个布尔值,表示是否要创建只读的代理对象。
      • baseHandlers:一个处理常规对象属性变化的处理器集合。
      • collectionHandlers:一个处理集合对象属性变化的处理器集合。
      • proxyMap:一个 WeakMap,用于存储对象与它们的代理之间的映射关系。
  2. 实现逻辑:

    • 首先,函数会检查 target 是否是一个普通的基本数据类型,如果是,会在开发环境下发出警告,并返回 target 本身。这是为了确保只有对象才会被代理,基本数据类型不会被代理。

    • 接着,函数检查 target 是否已经被代理过,如果是并且不是为了将响应式对象变成只读的(即 isReadonlyfalse),则直接返回 target 本身。这是一种性能优化,避免重复代理已经被代理过的对象。

    • 如果 target 还没有被代理过,函数会继续进行以下操作:

      • 调用 getTargetType 函数,该函数根据目标对象的类型,返回一个值,指示目标对象的类型。具体来说,如果 target 是普通对象或数组,它会返回 TargetType.COMMON;如果是集合对象(如 Map、Set 等),则返回 TargetType.COLLECTION;否则,返回 TargetType.INVALID

      • 如果 targetTypeTargetType.INVALID,则说明 target 的类型不在白名单中,不能被代理,直接返回 target 本身。

      • 最后,使用 new Proxy 创建一个代理对象 proxy,并根据 targetType 选择相应的处理器集合(baseHandlerscollectionHandlers)来处理属性的变化。然后,将 proxy 缓存到 proxyMap 中,以便下次再次代理相同的 target 时可以直接返回缓存的 proxy

  3. 总结:

    • createReactiveObject 是 Vue 3 响应式系统的核心函数之一,它用于创建深度响应式代理对象。函数会检查目标对象是否已经被代理过,如果已经被代理则直接返回,避免不必要的重复代理。如果目标对象是在白名单中的可代理类型,那么就创建一个代理对象,并将其缓存,以便后续使用。

相关文章:

【Vue3 源码解析】reactive 全家桶

// 泛型约束&#xff1a;只能传入引用类型 export function reactive<T extends object>(target: T): UnwrapNestedRefs<T> // 判断只读&#xff0c;否则创建reactive响应式对象 export function reactive(target: object) {// if trying to observe a readonly pr…...

目标检测YOLO实战应用案例100讲-基于YOLO的遥感目标检测(续)

目录 3.4 YOLOv3 3.5 YOLOv4 3.6 YOLOv5 改进的YOLOv4算法 4.1 Triple Loss损失函数的应用...

7.5 通过API判断进程状态

进程状态的判断包括验证进程是否存在&#xff0c;实现方法是通过枚举系统内的所有进程信息&#xff0c;并将该进程名通过CharLowerBuff转换为小写&#xff0c;当转换为小写模式后则就可以通过使用strcmp函数对比&#xff0c;如果发现继承存在则返回该进程的PID信息&#xff0c;…...

你写过的最蠢的代码是?

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…...

MySQL与PostgreSQL对比

MySQLPostgreSQL数据类型支持支持JSON&#xff0c;但不如PostgreSQL支持更多的数据类型&#xff0c;如数组、hstore、JSON、JSONB、范围类型等扩展性有一些扩展性&#xff0c;但不如PostgreSQL支持自定义数据类型、函数、操作符&#xff0c;具有强大的扩展性SQL兼容性遵循SQL标…...

AD拼板技巧

AD拼板设置 如图&#xff0c;有一个需要拼板的PCB&#xff0c;想要在生产是拼接生产&#xff0c;节省材料。 操作如下&#xff1a; 1、全选如下&#xff0c;按复制CtrlC。 2、把输入法调整至英文&#xff0c;按快捷键E&#xff08;先&#xff09;&#xff0c; A&#xff08;后…...

Android滑动片段

本文所有的代码均存于 https://github.com/MADMAX110/BitsandPizzas 回到BitsandPizzas应用&#xff0c;之前已经创建过创建订单和发出反馈等功能。 修改披萨应用&#xff0c;让它使用标签页导航。在工具条下显示一组标签页&#xff0c;每个选项对应一个不同的标签页。用户单击…...

【力扣-每日一题】337. 打家劫舍 III

class Solution { public:pair<int,int> dfs_rob(TreeNode *root){//如果为根节点if(rootnullptr)return {0,0};auto [l,l_n]dfs_rob(root->left);auto [r,r_n]dfs_rob(root->right);int ol_nr_nroot->val;//当前节点偷&#xff0c;所获得的利益,子节点不能偷in…...

Docker部署FastDFS分布式存储

1、准备工作 docker pull qinziteng/fastdfs:5.05 Pwd"/data/software/fastdfs" mkdir ${Pwd}/{storage,tracker} -p2、创建TEST容器&#xff0c;将fastdfs目录COPY到本地&#xff0c;方便后续维护管理&#xff01; docker run -id --name fastdfs qinziteng/fastd…...

MyBatis基础之SqlSession

SqlSession 线程安全问题 当你翻看 SqlSession 的源码时&#xff0c;你会发现它只是一个接口。我们通过 MyBatis 操作数据库&#xff0c;实际上就是通过 SqlSession 获取一个 JDBC 链接&#xff0c;然后操作数据库。 SqlSession 接口有 3 个实现类&#xff1a; #实现类1Defa…...

笔记本电脑没有麦克风,声音无法找到输入设备

新买的电脑没有扬声器&#xff0c;电脑声音没有输入设备&#xff0c;在开腾讯会议的时候才发现竟然有这个问题。 网上找原因&#xff0c;哎&#xff0c;找了一大堆每一个靠谱的 这让我想起来上次电脑没有热键的问题&#xff0c;所有问题的终极解决方案&#xff0c;都在源头那里…...

MySQL基础—从零开始学习MySQL

01.MySQL课程介绍_哔哩哔哩_bilibili 1、MySQL安装 以管理员身份运行cmd net start mysql80net stop mysql80 客户端连接 1). 方式一&#xff1a;使用MySQL提供的客户端命令行工具 2). 方式二&#xff1a;使用系统自带的命令行工具执行指令 mysql [-h 127.0.0.1] [-P 3…...

单例模式设计

目标&#xff1a; 1. 饿汉模式 2. 懒汉模式 3. 饿汉模式优化 目录 饿汉模式 懒汉模式 懒汉模式优化 饿汉模式 由名字我们就可以知道 "饿汉" 嘛&#xff0c;就比较急切&#xff0c;在类加载的时候就创建实例&#xff1a; 1. 写一个类&#xff0c;在本类中构造实…...

轻量型服务器能支撑多少人访问?

一、服务器配置影响访问人数 服务器的配置是影响轻量型服务器能够支撑的访问人数的关键因素之一。通常而言&#xff0c;轻量型服务器的配置普遍不高&#xff0c;适合小型团队或个人使用。如果服务器配置较低&#xff0c;那么支撑访问人数的能力也会受到限制。较为简单的应用程序…...

python: Sorting Algorithms

# encoding: utf-8 # 版权所有 2023 涂聚文有限公司 # 许可信息查看&#xff1a;Python Sorting Algorithms # 描述&#xff1a; * https://www.programiz.com/dsa/counting-sort # * https://www.geeksforgeeks.org/sorting-algorithms/ # Author : geovindu,Geovin Du 涂…...

Python 安装js环境

在终端执行下面的命令 npm install jsdom jsdom 是一个实现了 DOM API 的 JavaScript 环境&#xff0c;用于在 Node.js 中模拟浏览器的 DOM 环境。execjs 使用 jsdom 这个模块来执行 JavaScript 代码。所以在你的系统中&#xff0c;需要先安装并配置好 jsdom 模块&#xff0c…...

2023华为杯数模C题——大规模创新类竞赛评审方案研究

B题——大规模创新类竞赛评审方案研究 思路&#xff1a;采用数据分析等手段改进评分算法性能 完成情况(1-2问已经完成) 代码下载 问题一 在每个评审阶段&#xff0c;作品通常都是随机分发的&#xff0c;每份作品需要多位评委独立评审。为了增加不同评审专家所给成绩之间的可比…...

人工神经网络ANN:数学总结

一、内容 径向基函数&#xff08;Radial basis function&#xff0c;RBF&#xff09;&#xff1a;一个取值仅依赖于到原点距离的实值函数&#xff0c;即。此外&#xff0c;也可以按到某一中心点c的距离来定义&#xff0c;即。 可以用于许多向函基数的和来逼近某一给定的函数&a…...

RabbitMQ的工作模式——WorkQueues

1.工作队列模式 生产者代码 public class Producer_WorkQueues1 {public static void main(String[] args) throws IOException, TimeoutException {//1.创建连接工厂ConnectionFactory factory new ConnectionFactory();//2.设置参数factory.setHost("172.16.98.133&qu…...

AOJ 0531 坐标离散化

一、题目大意 在(0<x<w&#xff0c;0<y<h)的坐标系里有多个矩形&#xff0c;把区域分成了多个部分&#xff0c;我们需要针对找出被矩形分割的连通的区块数量。 二、解题思路 这个题目其实和学DFS时候那个找出连通的水洼是一样的。只是这个地图比较大&#xff0c…...

融合 PSO 的改进鲸鱼优化算法(PSO‑ImWOA)无人机三维航迹规划研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

I2C总线原理与应用实战指南

1. I2C总线基础概念解析I2C&#xff08;Inter-Integrated Circuit&#xff09;总线是飞利浦半导体&#xff08;现NXP&#xff09;在1980年代开发的一种同步、多主从架构的串行通信总线。作为一名嵌入式工程师&#xff0c;我几乎在每个项目中都会用到这个看似简单却功能强大的两…...

设置 Docker 化的 Python 环境 — 优雅的方式

原文&#xff1a;towardsdatascience.com/setting-a-dockerized-python-environment-the-elegant-way-f716ef85571d?sourcecollection_archive---------1-----------------------#2024-04-02 本文提供了一个逐步指南&#xff0c;介绍如何使用 VScode 和 Dev Containers 扩展设…...

【LeetCode】双指针专项合集

前言 本章练习&#xff1a;双指针&#xff1a;左右碰撞指针 目的&#xff1a;掌握左右指针向中间移动&#xff0c;最终相会的解法。 在下面这几道题中&#xff1a;思考不同题目中指针移动逻辑有什么区别 125&#xff1a;验证回文串 题目要求&#xff1a; 判断一个字符串是否是回…...

从LTE到5G NR:OFDM采样率与带宽设计的演进与挑战

1. LTE时代的OFDM参数设计&#xff1a;稳定但受限的起点 记得我第一次调试LTE基站时&#xff0c;被30.72MHz这个神奇的数字困扰了很久。为什么偏偏是这个采样频率&#xff1f;这要从LTE的OFDM基础设计说起。在LTE系统中&#xff0c;子载波间隔被固定为15kHz&#xff0c;就像用尺…...

介绍一下多 Agent 如何实现工作?多个 Agent 之间如何协调和分工?

1. 题目分析 一个 Agent 能做的事情终归有限。当你试图让单个 Agent 去完成一个真正复杂的任务——比如从零开始做一次完整的市场调研并输出 PPT 报告——你会发现它要么因为上下文窗口塞满而"失忆"&#xff0c;要么因为角色定位太泛而每一步都做得半吊子。这就像让…...

钻床夹具(说明书+装配图)

钻床夹具是机械加工中提升钻孔精度与效率的关键工具。其核心作用在于通过精准定位与可靠夹紧&#xff0c;确保工件在钻孔过程中保持稳定&#xff0c;避免因振动或位移导致的孔位偏差。传统钻孔作业依赖人工反复校准&#xff0c;不仅效率低下&#xff0c;且难以保证批量加工的一…...

三自由度车辆仿真融合Matlab与carsim,融合EKF/UKF与积分法测量质心侧偏角、纵向...

matlab和carsim联合仿真&#xff0c;基于三自由度车辆模型&#xff0c;搭建ekf或者ukf与积分法融合的用于测量质心侧偏角&#xff0c;纵向速度&#xff0c;横摆角速度。清晨六点半的实验室键盘声格外清脆&#xff0c;我盯着屏幕里那辆在CarSim里蛇形走位的虚拟高尔夫&#xff0…...

AI时代的算法思维:大经典排序学习矩

引言 在现代软件开发中&#xff0c;性能始终是衡量应用质量的重要指标之一。无论是企业级应用、云服务还是桌面程序&#xff0c;性能优化都能显著提升用户体验、降低基础设施成本并增强系统的可扩展性。对于使用 C# 开发的应用程序而言&#xff0c;性能优化涉及多个层面&#x…...

Blue-Topaz主题快速上手:打造个性化Obsidian笔记环境

Blue-Topaz主题快速上手&#xff1a;打造个性化Obsidian笔记环境 【免费下载链接】Blue-Topaz_Obsidian-css A blue theme for Obsidian. 项目地址: https://gitcode.com/gh_mirrors/bl/Blue-Topaz_Obsidian-css Blue-Topaz是一款为Obsidian设计的蓝色主题&#xff0c;…...