使用 ES6 Proxy 实现极简响应式系统 -1
1. Proxy 基础概念
1.1 什么是 Proxy
-
ES6 新增的元编程特性
-
用于创建对象的代理,拦截并自定义对象的基本操作
1.2 核心语法
const proxy = new Proxy(target, handler)
-
target: 要代理的目标对象 -
handler: 包含拦截器(traps)的对象
1.3 常用拦截器
-
get(target, property): 拦截属性读取 -
set(target, property, value): 拦截属性设置 -
has(target, property): 拦截in操作符
2. 实现目标
-
创建响应式对象,当属性变化时自动触发回调
-
支持功能:
-
监听对象属性变化
-
支持嵌套对象监听
-
变化时触发回调函数
-
3. 实现步骤详解
3.1 定义响应式系统的基本结构
我们需要一个函数
reactive,它接受一个对象作为参数,并返回一个响应式代理对象。同时,我们需要一个机制来存储和触发回调函数。function reactive(obj, callback) {
const handler = {
get(target, prop, receiver) {
// 处理嵌套对象
if (typeof target[prop] === 'object' && target[prop] !== null) {
return reactive(target[prop], callback);
}
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
callback(prop, value); // 触发回调
return Reflect.set(target, prop, value, receiver);
}
};
return new Proxy(obj, handler);
}
3.2 依赖收集与触发
// 创建响应式对象
const data = reactive(
{ count: 0, user: { name: 'John' } },
(key, value) => console.log(`[Update] ${key} => ${value}`)
)
// 测试
data.count = 1 // 输出: [Update] count => 1
data.user.name = 'Jane' // 输出: [Update] name => Jane
4. 完整代码示例
const createReactive = (initialData, callback) => {
const handler = {
get(target, key) {
const value = target[key]
if (typeof value === 'object' && value !== null) {
return new Proxy(value, handler)
}
return value
},
set(target, key, value) {
const oldValue = target[key]
target[key] = value
if (oldValue !== value) {
callback({
target,
key,
oldValue,
newValue: value
})
}
return true
}
}
return new Proxy(initialData, handler)
}
// 使用示例
const reactiveData = createReactive(
{ score: 100, items: [] },
({ key, newValue }) => console.log(`${key} changed to ${newValue}`)
)
reactiveData.score = 90 // 输出: score changed to 90
// 注意:数组方法需要特殊处理
reactiveData.items.push(1); // 输出: 0 changed to 1
reactiveData.items.push(2, 3); // 输出: 1 changed to 2 2 changed to 3
5. 优缺点与适用场景
优点:
-
自动深度响应
-
支持动态新增属性
-
原生支持数组变化检测
缺点:
-
无法检测直接操作数组索引的变化(需手动处理)
-
兼容性问题(不支持 IE11)
-
性能开销比 Object.defineProperty 大
适用场景:
-
中小型应用的响应式需求
-
需要动态新增属性的场景
-
需要深度监听嵌套对象的场景
6. 注意事项
-
性能优化:避免创建过多 Proxy 实例
-
数组处理:需拦截数组方法(push/pop 等)
-
循环引用:注意避免对象循环引用导致内存泄漏
-
浏览器兼容:需要 Babel 转译或 polyfill
扩展思考
-
如何实现自动依赖收集?
-
如何与虚拟 DOM 结合实现视图更新?
-
如何优化深层嵌套对象的性能?

浙公网安备 33010602011771号