Proxy 是 JavaScript 中用于拦截和自定义对象基本操作的构造器,它通过 handler 拦截 get、set、has、deleteProperty 等关键操作,实现响应式系统;相比 Object.defineProperty,Proxy 支持动态属性、数组索引、完整拦截能力且无需预设字段。
Proxy 是 JavaScript 中用于拦截和自定义对象基本操作的构造器,它是实现数据响应式的核心机制之一。 它不修改原对象,而是创建一个“代理”,在访问、赋值、删除等操作发生时插入自定义逻辑——这正是 Vue 3 和许多现代响应式库的底层基础。
通过 handler 对象,你可以捕获对目标对象的各种行为。最常用的是:
下面是一个能自动触发更新的 reactive 函数,配合 effect 实现依赖追踪:
const depsMap = new WeakMap(); // 存储 {target: Map>}
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key); // 收集当前 effect 依赖
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发所有依赖该 key 的 effect
return result;
}
});
}
function effect(fn) {
activeEffect = fn;
fn(); // 执行一次,触发内部的 get 收集依赖
activeEffect = null;
}
let activeEffect = null;
function track(target, key) {
if (!activeEffect) return;
let deps = depsMap.get(target);
if (!deps) {
deps = new Map();
depsMap.set(target, deps);
}
let effects = deps.get(key);
if (!effects) {
effects = new Set();
deps.set(key, effects);
}
effects.add(activeEffect);
}
function trigger(target, key) {
const deps = depsMap.get(target)?.get(key);
if (deps) deps.forEach(fn => fn());
}
使用示例:
const state = reactive({ count: 0 });
effect(() => {
console.log('count 变了:', state.count); // 初始输出 0
});
state.count++; // 自动触发 effect,输出 "count 变了:1"