Proxy 代理
Proxy
是 JavaScript 中的一个强大工具,用于定义对象的基本操作的自定义行为(如属性查找、赋值、枚举等)- 可以通过
Proxy
来拦截并重新定义对象的操作
创建
Proxy
的构造函数接受两个参数- 目标对象 (target): 你要代理的对象
- 处理器对象 (handler): 一个包含“拦截器”(trap)的对象,用于定义拦截行为
Proxy
构造函数需要使用 new 关键字调用,并且没有 prototype 属性
let proxy = new Proxy(target, handler);
logd(proxy); // 输出代理对象
常见拦截器(Traps)
get(target, prop, receiver)
: 拦截属性读取操作。set(target, prop, value, receiver)
: 拦截属性设置操作。has(target, prop)
: 拦截 in 操作符。deleteProperty(target, prop)
: 拦截 delete 操作符。apply(target, thisArg, argumentsList)
: 拦截函数调用。ownKeys(target)
: 拦截 Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols。
1.get
- 定义一个
get
拦截器,用于拦截属性读取操作
let handler = {
get: function(target, prop) {
logd(`Reading property: ${prop}`);
return target[prop];
}
};
let proxy = new Proxy({}, handler);
logd(proxy.example);
// 输出: Reading property: example
// 输出: undefined
2. set
- 定义一个
set
拦截器,用于拦截属性设置操作
let handler = {
set: function (target, prop, value) {
logd(`Setting property: ${prop} to ${value}`);
target[prop] = value;
return true;
}
};
let proxy = new Proxy({}, handler);
proxy.example = 'test'; // 输出: Setting property: example to test
3. has
- 定义一个
has
拦截器,用于拦截 in 操作符
let handler = {
has: function(target, prop) {
logd(`Checking if property exists: ${prop}`);
return prop in target;
}
};
let proxy = new Proxy({ example: true }, handler);
logd('example' in proxy);
// 输出: Checking if property exists: example
// 输出: true
4.deleteProperty
- 定义一个
deleteProperty
拦截器,用于拦截delete
操作符
let handler = {
deleteProperty: function(target, prop) {
logd(`Deleting property: ${prop}`);
delete target[prop];
return true;
}
};
let proxy = new Proxy({ example: true }, handler);
delete proxy.example; // 输出: Deleting property: example
5. apply
- 定义一个
apply
拦截器,用于拦截函数调用
let handler = {
apply: function(target, thisArg, argumentsList) {
logd('Applying function');
return Reflect.apply(target, thisArg, argumentsList);
}
};
let proxy = new Proxy(function() {}, handler);
proxy(); // 输出: Applying function
6. ownKeys
- 定义一个
ownKeys
拦截器,用于拦截Object.getOwnPropertyNames
和Object.getOwnPropertySymbols
操作
let handler = {
ownKeys: function(target) {
logd('Getting own keys');
return Reflect.ownKeys(target);
}
};
let proxy = new Proxy({ example: true }, handler);
logd(Object.getOwnPropertyNames(proxy));
// 输出: Getting own keys
// 输出: example
7. Proxy.revocable
Proxy.revocable
方法返回一个对象,该对象包含一个proxy
属性和一个revoke
方法- 可以使用
revoke
方法撤销代理,从而释放内存和资源 - 使用
revoke
方法后,代理将无法再被访问,并且无法再被撤销
let {proxy, revoke} = Proxy.revocable({}, {});
logd(proxy); // 输出: [object Object]
revoke(); // 撤销代理
logd(proxy); // 输出: TypeError: Illegal operation attempted on a revoked proxy
8. Arrays
Proxy
可以用于代理数组,从而实现一些特殊的操作,如拦截数组的索引访问、修改、删除等操作
let handler = {
get: function (target, prop) {
logd(`Reading array index: ${prop}`);
return target[prop];
}
};
let proxy = new Proxy([1, 2, 3], handler);
logd(proxy[0]);
// 输出: Reading array index: 0
// 输出: 1
示例
1. 拦截属性读 取和设置
let target = {
name: "Alice",
age: 25
};
let handler = {
get(target, prop) {
if (prop === 'age') {
return target[prop] + " years old";
}
return target[prop];
},
set(target, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
target[prop] = value;
return true; // 表示设置成功
}
};
let proxy = new Proxy(target, handler);
logd(proxy.age); // 输出: "25 years old"
proxy.age = 30;
logd(proxy.age); // 输出: "30 years old"
2. 拦截函数调用
let target = function (message) {
return `Hello, ${message}`;
};
let handler = {
apply(target, thisArg, argumentsList) {
let message = argumentsList[0];
return target(message.toUpperCase());
}
};
let proxy = new Proxy(target, handler);
logd(proxy("World")); // 输出: "Hello, WORLD"
3. 添加函数
let target = {
a: 1,
b: 2,
c: 3
};
let handler = {
get(target, prop) {
if (prop === 'sum') {
return function() {
let total = 0;
for (let key in target) {
if (target.hasOwnProperty(key)) {
total += target[key];
}
}
return total;
};
}
return target[prop];
}
};
let proxy = new Proxy(target, handler);
logd(proxy.sum()); // 输出: 6