JavaScript 代理与反射(Proxy/Reflect)
Proxy 用于拦截对象操作,Reflect 提供对应的反射方法,两者配合实现元编程。
Proxy 基础
JavaScript
const target = { name: 'Alice', age: 25 };
const proxy = new Proxy(target, {
get(obj, prop) {
console.log(`读取属性: ${prop}`);
return obj[prop];
},
set(obj, prop, value) {
console.log(`设置属性: ${prop} = ${value}`);
obj[prop] = value;
return true;
}
});
proxy.name; // 读取属性: name
proxy.age = 26; // 设置属性: age = 26
拦截操作
| 拦截方法 | 触发操作 |
|---|---|
get | 读取属性 proxy.key |
set | 设置属性 proxy.key = value |
has | in 操作符 key in proxy |
deleteProperty | delete proxy.key |
ownKeys | Object.keys(proxy) |
apply | 函数调用 proxy(...args) |
construct | new proxy(...args) |
常用拦截示例
属性验证
JavaScript
const validator = {
set(obj, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('age must be a number');
}
if (prop === 'age' && value < 0) {
throw new RangeError('age must be positive');
}
obj[prop] = value;
return true;
}
};
const person = new Proxy({}, validator);
person.age = 25; // OK
person.age = -1; // RangeError
私有属性
JavaScript
function createPrivate(obj) {
return new Proxy(obj, {
get(target, prop) {
if (prop.startsWith('_')) {
throw new Error('Cannot access private property');
}
return target[prop];
},
has(target, prop) {
if (prop.startsWith('_')) {
return false;
}
return prop in target;
}
});
}
函数拦截
JavaScript
function logCall(fn) {
return new Proxy(fn, {
apply(target, thisArg, args) {
console.log(`调用函数,参数: ${args}`);
return target.apply(thisArg, args);
}
});
}
const sum = logCall((a, b) => a + b);
sum(1, 2); // 调用函数,参数: 1,2
Reflect API
Reflect 提供与 Proxy 拦截器对应的方法:
JavaScript
const obj = { name: 'Alice' };
// 读取
Reflect.get(obj, 'name'); // 'Alice'
// 设置
Reflect.set(obj, 'age', 25); // true
// 检查存在
Reflect.has(obj, 'name'); // true
// 删除
Reflect.deleteProperty(obj, 'age'); // true
// 获取键列表
Reflect.ownKeys(obj); // ['name']
Proxy + Reflect 配合
JavaScript
const proxy = new Proxy({}, {
get(target, prop, receiver) {
console.log(`get: ${prop}`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`set: ${prop} = ${value}`);
return Reflect.set(target, prop, value, receiver);
}
});
使用 Reflect 可确保操作正确传播,支持原型链继承场景
可撤销代理
JavaScript
const { proxy, revoke } = Proxy.revocable({ name: 'Alice' }, {
get(target, prop) {
return target[prop];
}
});
proxy.name; // 'Alice'
revoke(); // 撤销代理
proxy.name; // TypeError: Cannot perform 'get' on a revoked proxy
要点总结
- Proxy 拦截对象操作,实现访问控制、日志、验证等
- Reflect 提供与 Proxy 对应的默认行为方法
- 13 种拦截操作覆盖几乎所有对象操作
Proxy.revocable()创建可撤销代理- Proxy + Reflect 是实现响应式框架的核心
📝 发现内容有误?点击此处直接编辑