✨ 基于Proxy · 优势
ES6 Proxy 取代 Object.defineProperty
- ✅ 拦截对象各种操作:读取(get)、设置(set)、删除(deleteProperty)、枚举(ownKeys) 等
- ✅ 全面监听:属性新增、删除、数组索引/length修改都能捕获
- ✅ 无需递归遍历所有属性,性能更优且支持动态属性
- ✅ 可拦截
in操作符、for...in等元操作
📋 对比Vue2:无法检测对象属性添加/删除,需用
$set;对数组需重写方法。Proxy完美解决。
📎 参考文献 [10]: Proxy可以拦截对象的各种操作,包括属性读取、设置、删除、枚举等,实现对对象变化的全面监听。
⚙️ 核心流程 · reactive + 依赖追踪
1️⃣ reactive(data) 创建代理对象
原始对象通过
new Proxy(target, handler) 变为响应式代理。▼
2️⃣ 组件渲染过程中访问响应式数据
例如模板中使用
{{ state.count }} 或 computed 中读取。▼
3️⃣ getter 拦截 → 依赖收集
触发Proxy的
get 陷阱,将当前副作用(如组件的渲染函数)记录为该属性的依赖。
🧠 依赖关系:target Map (属性 → Set(副作用))
▼
4️⃣ 响应式数据变化 🔁 setter 拦截
修改属性值触发
set 陷阱,比对变化后进入通知阶段。▼
5️⃣ 触发更新 (通知相关依赖)
从依赖映射中找到所有与该属性相关的副作用(组件渲染函数、计算属性等),加入调度队列。
▼
6️⃣ 组件重新渲染 · 更新DOM
执行副作用,生成新虚拟DOM,高效更新真实DOM。
⬇️ 依赖收集 在getter中建立关系
➡️
⬆️ 触发更新 在setter中派发任务
🔁 ref 包装基本类型
ref() 用于
string | number | boolean 等原始值
🔸 构造:
ref('hello')
⚡ 返回一个包含 .value 属性的对象:
{ value: 'hello' }
✨ 模板中自动解包
✅
<div>{{ msg }}</div> 无需写 msg.value
🧩 script中必须使用 .value 修改/读取
📦 同样基于Proxy/reactive实现,但通过value属性嵌套保证响应式
reactive vs ref
- reactive:用于对象/数组,直接代理
- ref:用于基本类型,也可包裹对象(但自动用reactive转换深层)