JavaScript中的Proxy与Reflect API详解
字数 507 2025-11-25 08:26:27
JavaScript中的Proxy与Reflect API详解
描述
Proxy和Reflect是ES6引入的元编程特性,允许你拦截并自定义对象的基本操作。Proxy用于创建对象的代理,可以拦截并重新定义对象的底层操作;Reflect提供了一组与Proxy拦截器对应的方法,用于执行对象的默认行为。
基本概念
- Proxy对象包装另一个对象,可以拦截如属性读取、赋值等操作
- 每个Proxy都需要一个"处理器"对象,定义拦截行为
- Reflect方法对应JavaScript内部方法,如[[Get]]、[[Set]]等
创建Proxy对象
const target = { name: 'John', age: 30 };
const handler = {
get(target, property, receiver) {
console.log(`读取属性: ${property}`);
return target[property];
},
set(target, property, value, receiver) {
console.log(`设置属性: ${property} = ${value}`);
target[property] = value;
return true; // 表示设置成功
}
};
const proxy = new Proxy(target, handler);
Proxy拦截器详解
- get拦截器 - 拦截属性读取
const handler = {
get(target, prop, receiver) {
if (prop in target) {
return Reflect.get(target, prop, receiver);
}
return `属性 ${prop} 不存在`;
}
};
- set拦截器 - 拦截属性赋值
const handler = {
set(target, prop, value, receiver) {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('年龄必须是数字');
}
return Reflect.set(target, prop, value, receiver);
}
};
- has拦截器 - 拦截in操作符
const handler = {
has(target, prop) {
if (prop.startsWith('_')) {
return false; // 隐藏私有属性
}
return Reflect.has(target, prop);
}
};
Reflect API的使用
Reflect方法通常与Proxy配合使用,确保正确的this绑定:
const handler = {
get(target, prop, receiver) {
// 使用Reflect确保receiver正确传递
return Reflect.get(target, prop, receiver);
}
};
实际应用场景
- 数据验证
const validator = {
set(target, prop, value) {
if (prop === 'email' && !value.includes('@')) {
throw new Error('无效的邮箱格式');
}
if (prop === 'age' && (value < 0 || value > 150)) {
throw new Error('年龄必须在0-150之间');
}
return Reflect.set(target, prop, value);
}
};
const user = new Proxy({}, validator);
- 负索引数组
function createNegativeArray(array) {
return new Proxy(array, {
get(target, prop, receiver) {
const index = Number(prop);
if (index < 0) {
prop = String(target.length + index);
}
return Reflect.get(target, prop, receiver);
}
});
}
const arr = createNegativeArray([1, 2, 3]);
console.log(arr[-1]); // 3(最后一个元素)
- 自动观察对象变化
function observable(target) {
const observers = new Set();
return new Proxy(target, {
set(target, prop, value, receiver) {
const oldValue = target[prop];
const result = Reflect.set(target, prop, value, receiver);
if (result && oldValue !== value) {
observers.forEach(observer => observer(prop, oldValue, value));
}
return result;
}
});
}
const obj = observable({ count: 0 });
// 可以添加观察者来监听变化
注意事项
- this绑定问题
const target = {
name: 'target',
getName() {
return this.name;
}
};
const proxy = new Proxy(target, {
get(target, prop, receiver) {
// 使用Reflect确保方法中的this指向proxy
const value = Reflect.get(target, prop, receiver);
return typeof value === 'function' ? value.bind(receiver) : value;
}
});
- 可撤销Proxy
const target = { message: 'hello' };
const { proxy, revoke } = Proxy.revocable(target, {});
console.log(proxy.message); // 'hello'
revoke(); // 撤销代理
// console.log(proxy.message); // 抛出TypeError
性能考虑
Proxy会带来一定的性能开销,在性能敏感的场景中应谨慎使用。但对于需要复杂拦截逻辑的场景,Proxy提供了更优雅的解决方案。