Vue3响应式原理那些事

文章目录

    • 1 响应式基础:Proxy 与 Reflect
      • 1.1 Proxy 代理拦截
      • 1.2 Reflect 确保 `this` 指向正确
        • 1.2.1 修正 `this` 指向问题
        • 1.2.2 统一的操作返回值
      • 1.3 与 Vue2 的对比
    • 2 依赖收集与触发机制
      • 2.1 全局依赖存储结构:WeakMap → Map → Set
      • 2.2 依赖收集触发时机
      • 2.3 依赖收集核心实现:track 函数
      • 2.4 依赖触发:trigger 函数
      • 2.5 副作用管理:ReactiveEffect 类
      • 2.6 特殊场景处理:ref 的依赖收集
      • 2.7 设计亮点
    • 3 响应式 API 的封装
      • 3.1. `reactive`
      • 3.2 `ref`
      • 3.3 `reactive` 与 `ref` 核心区别
      • 3.4 注意事项
    • 4 双向绑定实现(v-model)
      • 4.1 原生 DOM 元素的实现原理
        • 4.1.1 属性绑定
        • 4.1.2 响应式更新
      • 4.2 自定义组件的实现原理
        • 4.2.1 传统模式(Vue3.4 前)
        • 4.2.2 `defineModel` 宏(Vue3.4+)
      • 4.3 响应式系统的支撑
      • 4.4 性能优化与扩展性
    • 5 对比 Vue2 的改进

近期文章

  • Vue3开发常见性能问题知多少
  • Vue3组件常见通信方式你了解多少?
  • 实现篇:LRU算法的几种实现
  • 从底层视角看requestAnimationFrame的性能增强
  • Nginx Upstream了解一下
  • 实现篇:一文搞懂Promise是如何实现的
  • 实现篇:如何手动实现JSON.parse
  • 实现篇:如何亲手定制实现JSON.stringify
  • 一文搞懂 Markdown 文档规则

Vue3 的双向响应式原理是其核心机制,通过 Proxy 代理与 依赖收集系统 实现数据与视图的自动同步。以下是其核心原理与技术细节的深度解析:

1 响应式基础:Proxy 与 Reflect

Vue3 彻底抛弃了 Vue2 的 Object.defineProperty,改用 ES6 Proxy 实现数据劫持,解决了 Vue2 无法监听对象属性新增/删除、数组索引修改等问题。

1.1 Proxy 代理拦截

Proxy 可拦截对象的所有操作(如 getsetdeleteProperty 等),解决了 Vue2 中 Object.defineProperty 无法监听新增属性数组索引修改的问题。

Proxy 默认采用惰性代理,仅在访问嵌套对象时递归创建代理,优化了性能。

const handler = {get(target, key, receiver) {track(target, key); // 依赖收集return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {const result = Reflect.set(target, key, value, receiver);trigger(target, key); // 触发更新return result;}
};
const proxyData = new Proxy(data, handler);

1.2 Reflect 确保 this 指向正确

Reflect 的静态方法与 Proxy 的拦截器一一对应,确保操作的一致性和安全性:

1.2.1 修正 this 指向问题

当代理对象包含访问器属性(如 get c() { return this.a + this.b })时,若直接通过 target[key] 读取属性,this 会指向原对象而非代理对象,导致后续属性访问无法触发 Proxy 拦截。

解决方案:使用 Reflect.get(target, key, receiver),其中 receiver 显式传递代理对象,确保 this 指向正确。

 // 错误示例(this指向原对象)get(target, key) { return target[key]; }// 正确示例(通过Reflect修正this)get(target, key, receiver) { return Reflect.get(target, key, receiver); }
1.2.2 统一的操作返回值

Reflect 方法返回布尔值(如 Reflect.set() 返回操作是否成功),简化了错误处理流程。

1.3 与 Vue2 的对比

特性Vue2 (Object.defineProperty)Vue3 (Proxy + Reflect)
属性监听需遍历属性逐个劫持代理整个对象,自动处理新增/删除属性
数组支持需重写数组方法直接拦截原生数组操作
性能初始化递归遍历,性能较差惰性代理,按需触发拦截
代码复杂度需手动处理嵌套对象和数组原生支持复杂数据结构

2 依赖收集与触发机制

Vue3 的依赖收集机制通过 Proxy 拦截访问全局拓扑存储精准触发更新 的链路,实现了高效、精准的响应式更新。其 WeakMap 结构ReactiveEffect 双向链接惰性代理 等特性,使得框架具备更高的性能。

2.1 全局依赖存储结构:WeakMap → Map → Set

Vue3 使用三级数据结构管理依赖关系,确保高效的内存管理和精准的依赖追踪:

// 源码位置:packages/reactivity/src/effect.ts
type Dep = Set<ReactiveEffect>;
type KeyToDepMap = Map<any, Dep>;
const targetMap = new WeakMap<any, KeyToDepMap>(); // 全局依赖存储// 结构示意:
WeakMap {[targetObject]: Map {[key]: Set<effect1, effect2...>}
}
  • WeakMap:键为原始对象(避免内存泄漏),值为 KeyToDepMap
  • KeyToDepMap:键为对象属性名,值为 Dep(存储关联的副作用函数集合)。
  • DepSet<ReactiveEffect>,保证副作用的唯一性。

2.2 依赖收集触发时机

当访问响应式对象的属性时,Proxy 的 get 拦截器触发依赖收集流程:

// 源码简化:packages/reactivity/src/baseHandlers.ts
function createGetter() {return function get(target: object, key: string | 

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

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

相关文章

精选10个好用的WordPress免费主题

10个好用的WordPress免费主题 1. Astra Astra 是全球最受欢迎的WordPress免费主题。它功能丰富&#xff0c;易于使用&#xff0c;SEO友好&#xff0c;是第一个安装量突破100万的非默认主题&#xff0c;并获得了5000多个五星好评。 它完美集成了Elementor、Beaver&#xff0c;…

【SaaS多租架构】数据隔离与性能平衡

SaaS多租户架构:数据隔离与性能平衡 一、技术背景及发展二、技术特点:数据隔离与性能优化的双核心三、技术细节:实现路径与关键技术四、实际案例分析五、未来发展趋势结语一、技术背景及发展 多租户架构是云计算与SaaS(软件即服务)模式的核心技术,其核心目标是通过共享基…

部署GM DC Monitor 一体化监控预警平台

1&#xff09;首先在官网下载镜像文件 广目&#xff08;北京&#xff09;软件有限公司广目&#xff08;北京&#xff09;软件有限公司https://www.gm-monitor.com/col.jsp?id1142&#xff09;其次进行部署安装&#xff0c;教程如下&#xff1a; 1. 基础环境要求 1) 系统&…

Webug4.0靶场通关笔记15- 第19关文件上传(畸形文件)

目录 第19关 文件上传(畸形文件) 1.打开靶场 2.源码分析 &#xff08;1&#xff09;客户端源码 &#xff08;2&#xff09;服务器源码 3.渗透实战 &#xff08;1&#xff09;构造脚本 &#xff08;2&#xff09;双写绕过 &#xff08;3&#xff09;访问脚本 本文通过《…

架构思维:构建高并发读服务_热点数据查询的架构设计与性能调优

文章目录 一、引言二、热点查询定义与场景三、主从复制——垂直扩容四、应用内前置缓存4.1 容量上限与淘汰策略4.2 延迟刷新&#xff1a;定期 vs. 实时4.3 逃逸流量控制4.4 热点发现&#xff1a;被动 vs. 主动 五、降级与限流兜底六、前端&#xff0f;接入层其他应对七、模拟压…

宝塔面板运行docker的jenkins

1.在宝塔面板装docker&#xff0c;以及jenkins 2.ip:端口访问jenkins 3.获取密钥&#xff08;点击日志&#xff09; 4.配置容器内的jdk和maven环境&#xff08;直接把jdk和maven文件夹放到jenkins容器映射的data文件下&#xff09; 点击容器-->管理-->数据存储卷--.把相…

C语言 ——— 函数

目录 函数是什么 库函数 学习使用 strcpy 库函数 自定义函数 写一个函数能找出两个整数中的最大值 写一个函数交换两个整型变量的内容 牛刀小试 写一个函数判断一个整数是否是素数 写一个函数判断某一年是否是闰年 写一个函数&#xff0c;实现一个整型有序数组的二分…

笔记本电脑升级计划(2017———2025)

ThinkPad T470 (2017) vs ThinkBook 16 (2025) 完整性能对比报告 一、核心硬件性能对比 1. CPU性能对比&#xff08;i5-7200U vs Ultra9-285H&#xff09; 参数i5-7200U (2017)Ultra9-285H (2025)提升百分比核心架构2核4线程 (Skylake)16核16线程 (6P8E2LPE)700%核心数制程工…

具身系列——PPO算法实现CartPole游戏(强化学习)

完整代码参考&#xff1a; https://gitee.com/chencib/ailib/blob/master/rl/ppo_cartpole.py 执行结果&#xff1a; 部分训练得分&#xff1a; (sd) D:\Dev\traditional_nn\feiai\test\rl>python ppo_cartpole_v2_succeed.py Ep: 0 | Reward: 23.0 | Running: 2…

Python项目源码60:电影院选票系统1.0(tkinter)

1.功能特点&#xff1a;通常选票系统应该允许用户选择电影、场次、座位&#xff0c;然后显示总价和生成票据。好的&#xff0c;我得先规划一下界面布局。 首先&#xff0c;应该有一个电影选择的列表&#xff0c;可能用下拉菜单Combobox来实现。然后场次时间&#xff0c;可能用…

【全队项目】智能学术海报生成系统PosterGenius--图片布局生成模型LayoutPrompt(2)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;大模型实战训练营_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…

Linux的时间同步服务器(附加详细实验案例)

一、计时方式的发展 1.古代计时方式​ 公元前约 2000 年&#xff1a;古埃及人利用光线留下的影子计时&#xff0c;他们修建高耸的大型方尖碑&#xff0c;通过追踪方尖碑影子的移动判断时间&#xff0c;这是早期利用自然现象计时的典型方式 。​商朝时期&#xff1a;人们开发并…

【无需docker】mac本地部署dify

环境安装准备 #安装 postgresql13 brew install postgresql13 #使用zsh的在全局添加postgresql命令集 echo export PATH"/usr/local/opt/postgresql13/bin:$PATH" >> ~/.zshrc # 使得zsh的配置修改生效 source ~/.zshrc # 启动postgresql brew services star…

(5)概述 QT 的元对象系统里的类的调用与联系,及访问接口

&#xff08;1&#xff09; QT 的元对象系统&#xff0c;这几个字大家都知道&#xff0c;那么 QT 的元对象系统里都包含哪些内容呢&#xff0c;其访问接口是如何呢&#xff1f; 从 QObject 类的实现里&#xff0c;从其数据成员里就可以看出来&#xff1a; QT 里父容器可以释放其…

打包 Python 项目为 Windows 可执行文件:高效部署指南

Hypackpy 是一款由白月黑羽开发的 Python 项目打包工具&#xff0c;它与 PyInstaller 等传统工具不同&#xff0c;通过直接打包解释器环境和项目代码&#xff0c;并允许开发者修改配置文件以排除不需要的内容&#xff0c;从而创建方便用户一键运行的可执行程序。以下是使用 Hyp…

MySQL JOIN详解:掌握数据关联的核心技能

一、为什么需要JOIN&#xff1f; 在关系型数据库中&#xff0c;数据通常被拆分到不同的表中以提高存储效率。当我们需要从多个表中组合数据时&#xff0c;JOIN操作就成为了最关键的技能。通过本文&#xff0c;您将全面掌握MySQL中7种JOIN操作&#xff0c;并学会如何在实际场景中…

Kdump 收集器及使用方式

以下是 Linux 系统中 Kdump 转储收集器的详细说明及其使用方法&#xff0c;涵盖核心工具、配置方法及实际示例&#xff1a; 一、Kdump 收集器分类及作用 Kdump 的核心功能是通过 捕获内核 生成内存转储文件&#xff08;vmcore&#xff09;&#xff0c;其核心收集器包括&#…

Error: error:0308010C:digital envelope routines::unsupported 高版本node启动低版本项目运行报错

我的问题就是高版本node启动旧版本项目引起的问题&#xff0c;单独在配置 package.json文件中配置并运行就可以&#xff0c;大概意思就是设置node的openssl "scripts": {"dev": "SET NODE_OPTIONS--openssl-legacy-provider && vue-cli-servi…

松下机器人快速入门指南(2025年更新版)

松下机器人快速入门指南&#xff08;2025年更新版&#xff09; 松下机器人以其高精度、稳定性和易用性在工业自动化领域广泛应用。本文将从硬件配置、参数设置、手动操作、编程基础到维护保养&#xff0c;全面讲解松下机器人的快速入门方法&#xff0c;帮助新手快速掌握核心操…

【CISCO】Se2/0, Se3/0:串行口(Serial) 这里串口的2/0 和 3/0分别都是什么?

在 Cisco IOS 设备上&#xff0c;接口名称通常遵循这样一个格式&#xff1a; <类型><槽号>/<端口号>类型&#xff08;Type&#xff09;&#xff1a;表示接口的物理或逻辑类型&#xff0c;比如 Serial&#xff08;串行&#xff09;、FastEthernet、GigabitEt…