### 关于 Proxy 的 13 种拦截器
JavaScript 中的 `Proxy` 提供了多种拦截操作的方法,这些方法被称为 **拦截器** 或者 **陷阱 (traps)**。以下是完整的 13 种拦截器及其功能描述:
#### 1. `get(target, propKey, receiver)`
用于拦截对象属性的读取操作。
```javascript
const handler = {
get(target, propKey, receiver) {
console.log(`Getting ${propKey}`);
return Reflect.get(target, propKey, receiver);
}
};
let target = { name: 'Alice' };
let proxy = new Proxy(target, handler);
console.log(proxy.name); // 输出 "Getting name", 然后返回 Alice
```
[^1]
---
#### 2. `set(target, propKey, value, receiver)`
用于拦截对象属性的设置操作。
```javascript
const handler = {
set(target, propKey, value, receiver) {
console.log(`Setting ${propKey} to`, value);
return Reflect.set(target, propKey, value, receiver);
}
};
let target = {};
let proxy = new Proxy(target, handler);
proxy.name = 'Bob'; // 设置并打印日志
console.log(proxy.name); // Bob
```
---
#### 3. `has(target, propKey)`
用于拦截 `in` 操作符。
```javascript
const handler = {
has(target, propKey) {
if (propKey === 'secret') {
return false;
}
return Reflect.has(target, propKey);
}
};
let target = { secret: true };
let proxy = new Proxy(target, handler);
console.log('secret' in proxy); // false
console.log('name' in proxy); // 如果有其他键,则正常返回
```
[^2]
---
#### 4. `deleteProperty(target, propKey)`
用于拦截 `delete obj[propKey]` 操作。
```javascript
const handler = {
deleteProperty(target, propKey) {
console.log(`Deleting property ${propKey}`);
return Reflect.deleteProperty(target, propKey);
}
};
let target = { a: 1 };
let proxy = new Proxy(target, handler);
delete proxy.a; // 删除并记录日志
console.log('a' in proxy); // false
```
---
#### 5. `ownKeys(target)`
用于拦截 `Object.getOwnPropertyNames(obj)` 和 `JSON.stringify()` 等获取目标对象自身属性的操作。
```javascript
const handler = {
ownKeys(target) {
return ['foo', 'bar'];
}
};
let target = {};
let proxy = new Proxy(target, handler);
console.log(Object.keys(proxy)); // ["foo", "bar"]
```
---
#### 6. `apply(target, thisArg, argumentsList)`
用于拦截函数调用操作。
```javascript
function sum(a, b) {
return a + b;
}
const handler = {
apply(target, thisArg, args) {
console.log(args);
return Reflect.apply(...arguments);
}
};
let proxy = new Proxy(sum, handler);
console.log(proxy(1, 2)); // 打印参数 [1, 2], 返回 3
```
---
#### 7. `construct(target, argArray, newTarget)`
用于拦截通过 `new` 调用构造函数的行为。
```javascript
class MyClass {}
const handler = {
construct(target, args, newTarget) {
console.log('Creating instance with:', args);
return Reflect.construct(target, args, newTarget);
}
};
let proxy = new Proxy(MyClass, handler);
new proxy(); // 创建实例时触发日志
```
---
#### 8. `defineProperty(target, propKey, attributes)`
用于拦截 `Object.defineProperty(obj, key, desc)` 操作。
```javascript
const handler = {
defineProperty(target, propKey, attributes) {
console.log(`Defining property ${propKey}`, attributes);
return Reflect.defineProperty(target, propKey, attributes);
}
};
let target = {};
let proxy = new Proxy(target, handler);
Object.defineProperty(proxy, 'test', { configurable: true });
// 定义 test 属性并打印日志
```
---
#### 9. `getOwnPropertyDescriptor(target, propKey)`
用于拦截 `Object.getOwnPropertyDescriptor(obj, propKey)` 操作。
```javascript
const handler = {
getOwnPropertyDescriptor(target, propKey) {
const descriptor = Reflect.getOwnPropertyDescriptor(target, propKey);
if (descriptor !== undefined && typeof descriptor.value === 'number') {
descriptor.value *= 2;
}
return descriptor;
}
};
let target = { num: 10 };
let proxy = new Proxy(target, handler);
console.log(Object.getOwnPropertyDescriptor(proxy, 'num')); // {value: 20, ...}
```
---
#### 10. `isExtensible(target)`
用于拦截 `Object.isExtensible(obj)` 操作。
```javascript
const handler = {
isExtensible(target) {
console.log('Checking extensibility');
return Reflect.isExtensible(target);
}
};
let target = {};
let proxy = new Proxy(target, handler);
console.log(Object.isExtensible(proxy)); // true 并打印日志
```
---
#### 11. `preventExtensions(target)`
用于拦截 `Object.preventExtensions(obj)` 操作。
```javascript
const handler = {
preventExtensions(target) {
console.log('Preventing extensions');
return Reflect.preventExtensions(target);
}
};
let target = {};
let proxy = new Proxy(target, handler);
Object.preventExtensions(proxy); // 阻止扩展并打印日志
```
---
#### 12. `getPrototypeOf(target)`
用于拦截 `Object.getPrototypeOf(obj)` 操作。
```javascript
const handler = {
getPrototypeOf(target) {
console.log('Fetching prototype...');
return Reflect.getPrototypeOf(target);
}
};
let target = Object.create({ foo: 'bar' });
let proxy = new Proxy(target, handler);
console.log(Object.getPrototypeOf(proxy)); // 获取原型链上的对象
```
---
#### 13. `setPrototypeOf(target, proto)`
用于拦截 `Object.setPrototypeOf(obj, proto)` 操作。
```javascript
const handler = {
setPrototypeOf(target, proto) {
console.log('Changing prototype...');
return Reflect.setPrototypeOf(target, proto);
}
};
let target = {};
let proxy = new Proxy(target, handler);
Object.setPrototypeOf(proxy, null); // 更改原型并打印日志
```
---
### 总结
以上列举了 JavaScript 中 `Proxy` 支持的所有 13 种拦截器,并提供了每种拦截器的具体实现方式和实际应用案例。