一、Proxy 核心原理
1.1 基础概念
Proxy 是 ES6 引入的元编程特性,通过创建代理对象拦截目标对象(target)的操作。其工作机制可概括为:
ini
javascript
const proxy = new Proxy(target, handler);
- 目标对象(target) :被代理的原始对象
- 处理器对象(handler) :定义拦截行为的配置对象,包含 13 种捕获器(traps)
1.2 内部方法映射
Proxy 通过内部方法实现操作拦截,常见映射关系如下:
内部方法 | 对应捕获器 | 触发场景 |
---|---|---|
[[Get]] | get | 属性读取 obj.prop |
[[Set]] | set | 属性赋值 obj.prop = v |
[[Apply]] | apply | 函数调用 fn(...args) |
[[HasProperty]] | has | in 操作符 prop in obj |
1.3 执行流程示例
ini
javascript
const target = { name: "Alice" };
const handler = {
get(target, prop) {
console.log(`Reading ${prop}`);
return target[prop];
}
};
const proxy = new Proxy(target, handler);
proxy.name; // 输出:Reading name → "Alice"
二、核心捕获器详解
2.1 get 捕获器(属性读取)
应用场景:依赖收集、懒加载
javascript
javascript
// Vue 3 响应式简化版
function reactive(target) {
return new Proxy(target, {
get(target, prop, receiver) {
trackDependency(prop); // 收集依赖
return Reflect.get(target, prop, receiver);
}
});
}
2.2 set 捕获器(属性设置)
应用场景:数据验证、自动更新
javascript
javascript
const user = new Proxy({}, {
set(target, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
throw new Error('年龄必须为数字');
}
triggerUpdate(prop); // 触发更新
target[prop] = value;
return true;
}
});
2.3 apply 捕获器(函数调用)
应用场景:防抖/节流封装
javascript
javascript
// 防抖函数封装
function debounce(fn, delay = 300) {
let timer;
return new Proxy(fn, {
apply(target, ctx, args) {
clearTimeout(timer);
timer = setTimeout(() => Reflect.apply(target, ctx, args), delay);
}
});
}
三、典型应用场景
3.1 响应式系统实现
Vue 3 对比 Vue 2:
javascript
javascript
// Vue 2(Object.defineProperty 缺陷)
Object.defineProperty(obj, 'prop', {
get() { /* 无法监听新增属性 */ },
set() { /* 需手动处理数组变化 */ }
})
// Vue 3(Proxy 优势)
const state = reactive({ count: 0 });
effect(() => {
console.log(state.count); // 自动收集依赖
});
3.2 数据权限控制
javascript
javascript
const secureObj = new Proxy({ secret: '123' }, {
get(target, prop) {
if (prop === 'secret' && !isAdmin) {
throw new Error('无权限访问');
}
return target[prop];
}
});
3.3 函数式编程优化
javascript
javascript
// 不可变数据结构
const immutableData = new Proxy(originalData, {
set() {
throw new Error('数据不可修改');
}
});
四、性能与兼容性
4.1 性能优势
-
批量操作优化:Proxy 的 set 捕获器可合并多次更新:
markdownjavascript const optimizedObj = new Proxy({}, { set(target, prop, value) { requestAnimationFrame(() => { target[prop] = value; render(); }); return true; } });
4.2 兼容性考虑
-
浏览器支持:Chrome 49+/Firefox 18+/Safari 10+
-
降级方案:
javascriptjavascript const fallback = obj => Proxy ? new Proxy(obj, handler) : obj;
五、进阶实践案例
5.1 深度监听实现
ini
javascript
const deepReactive = (target) => {
return new Proxy(target, {
get(target, prop) {
const value = target[prop];
return typeof value === 'object' ? deepReactive(value) : value;
},
set(target, prop, value) {
target[prop] = value;
triggerDeepUpdate(prop);
return true;
}
});
};
5.2 接口调用封装
javascript
javascript
const apiProxy = new Proxy(() => {}, {
apply(target, ctx, [url, config]) {
return fetch(url, config)
.then(res => res.json())
.catch(handleError);
}
});
六、总结
Proxy 通过强大的拦截机制重新定义了 JavaScript 对象操作方式,其核心价值体现在:
- 统一操作拦截:替代 Vue 2 的递归属性监听
- 动态行为扩展:如防抖函数、权限控制
- 性能优化空间:批量更新、懒加载
- 代码简洁性:减少 70%+ 的响应式代码