响应式系统实现深度解析
核心思想:聚焦能力
- 问题拆解:将复杂问题分解为独立子目标,逐个击破
- 精力分配:集中有限资源攻克关键点,避免分散
- 实践验证:在代码实现中反复验证认知,逐步完善设计
核心能力实现
1. 监听(Tracking)
关键实现
const targetMap = new WeakMap()
function reactive(target) {
if (!isObject(target)) return target
if (targetMap.has(target)) return targetMap.get(target)
const proxy = new Proxy(target, handlers)
targetMap.set(target, proxy)
return proxy
}
关键技术点
- WeakMap缓存:解决重复代理问题,防止内存泄漏
- 边界处理:非对象直接返回
- 模块分离:代理处理逻辑抽离到handlers模块
2. 读取(Read)
处理类型
操作类型 | 对应场景 | 内部方法 |
---|---|---|
trackOpTypes.GET | 属性访问 obj.a | [[Get]] |
trackOpTypes.HAS | in 操作符 | [[Has]] |
trackOpTypes.ITERATE | for...in 循环 | [[OwnKeys]] |
代码实现
// handlers.js
const handlers = {
get(target, key, receiver) {
track(target, trackOpTypes.GET, key)
const value = Reflect.get(target, key, receiver)
return isObject(value) ? reactive(value) : value
},
has(target, key) {
track(target, trackOpTypes.HAS, key)
return Reflect.has(target, key)
},
ownKeys(target) {
track(target, trackOpTypes.ITERATE)
return Reflect.ownKeys(target)
}
}
关键技术点
- Reflect的使用:正确传递receiver保证this指向
- 深度代理:递归处理对象属性
- 操作类型区分:精确追踪不同读取场景
3. 修改(Write)
处理类型
操作类型 | 触发场景 | 内部方法 |
---|---|---|
triggerOpTypes.SET | 属性修改 obj.a = 1 | [[Set]] |
triggerOpTypes.ADD | 新增属性 obj.b = 2 | [[Set]] |
triggerOpTypes.DELETE | 删除属性 delete obj.c | [[Delete]] |
代码实现
// handlers.js
const handlers = {
set(target, key, value, receiver) {
const oldValue = target[key]
const hadKey = Object.prototype.hasOwnProperty.call(target, key)
const result = Reflect.set(target, key, value, receiver)
if (!result) return result
const type = hadKey
? triggerOpTypes.SET
: triggerOpTypes.ADD
if (!hadKey || hasChanged(value, oldValue)) {
trigger(target, type, key)
}
return result
},
deleteProperty(target, key) {
const hadKey = Object.prototype.hasOwnProperty.call(target, key)
const result = Reflect.deleteProperty(target, key)
if (hadKey && result) {
trigger(target, triggerOpTypes.DELETE, key)
}
return result
}
}
// utils.js
export function hasChanged(value, oldValue) {
return !Object.is(value, oldValue)
}
关键技术点
- 变化检测:使用
Object.is
处理NaN和±0的特殊情况 - 类型判断:区分修改和新增操作
- 有效性验证:处理只读属性等边界情况
架构优化
模块化设计
src/
├── reactive.js # 主入口
├── handlers.js # Proxy处理函数
├── operations.js # 操作类型常量
└── utils.js # 工具函数
关键工具函数
// utils.js
export function isObject(value) {
return value !== null && typeof value === 'object'
}
export function hasChanged(value, oldValue) {
return !Object.is(value, oldValue)
}
深度思考
-
WeakMap vs Map
- 弱引用特性防止内存泄漏
- 适合建立对象与代理的映射关系
-
Reflect的必要性
- 正确传递receiver保持上下文
- 对齐Proxy handler方法参数
-
操作类型关联
for...in
→ 响应属性增删in
操作符 → 响应属性存在性变化- 属性读取 → 响应值变化
待处理问题(下节课内容)
- 数组方法的特殊处理(push/pop等)
- 嵌套数组的响应式处理
- 性能优化:避免重复触发依赖
- 循环引用处理
通过聚焦每个关键点的实现,逐步构建出完整的响应式系统。下节课将深入处理数组相关特性和性能优化。