ES6 引入了 Proxy 对象,它用于创建一个对象的代理,从而可以拦截并自定义对象的基本操作,如属性查找、赋值、枚举、函数调用等。
主要特性:
- 拦截操作:可以拦截对象的各种操作,如获取属性、设置属性、属性是否存在等。
- 自定义行为:通过拦截操作,可以自定义对象的行为。
- 撤销代理:可以撤销代理,恢复对象的原始行为。
Proxy 支持的拦截操作一览,一共 13 种:
- get(target, propKey, receiver):拦截对象属性的读取,比如 proxy.foo 和 proxy[‘foo’] 。
- set(target, propKey, value, receiver):拦截对象属性的设置,比如 proxy.foo = v 或 proxy[‘foo’] = v ,返回一个布尔值。
- has(target, propKey):拦截 propKey in proxy 的操作,返回一个布尔值。
- deleteProperty(target, propKey):拦截 delete proxy[propKey] 的操作,返回一个布尔值。
- ownKeys(target):拦截 Object.getOwnPropertyNames(proxy)
- Object.getOwnPropertySymbols(proxy) 、 Object.keys(proxy) 、 for…in 循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys() 的返回结果仅包括目标对象自身的可遍历属性。
- getOwnPropertyDescriptor(target, propKey):拦截 Object.getOwnPropertyDescriptor(proxy, propKey) ,返回属性的描述对象。
- defineProperty(target, propKey, propDesc):拦截 Object.defineProperty(proxy, propKey, propDesc) 、 Object.defineProperties(proxy, propDescs) ,返回一个布尔值。
- preventExtensions(target):拦截 Object.preventExtensions(proxy) ,返回一个布尔值。
- getPrototypeOf(target):拦截 Object.getPrototypeOf(proxy) ,返回一个对象。
- isExtensible(target):拦截 Object.isExtensible(proxy) ,返回一个布尔值。
- setPrototypeOf(target, proto):拦截 Object.setPrototypeOf(proxy, proto) ,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
- apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如
proxy(…args) 、 proxy.call(object, …args) 、 proxy.apply(…) 。
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如 new proxy(…args) 。
1:基本的属性拦截
let target = {};
let handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : `Property ${prop} not found`;
},
set: function(obj, prop, value) {
console.log(`Setting ${prop} with value ${value}`);
obj[prop] = value;
return true;
}
};
let proxy = new Proxy(target, handler);
proxy.name = "Alice"; // 输出: Setting name with value Alice
console.log(proxy.name); // 输出: Alice
console.log(proxy.age); // 输出: Property age not found
2:拦截in操作符
let target = { a: 1 };
let handler = {
has: function(target, prop) {
return prop in target || prop === 'extra';
}
};
let proxy = new Proxy(target, handler);
console.log('a' in proxy); // 输出:true
console.log('extra' in proxy); // 输出:true
console.log('b' in proxy); // 输出:false
3:拦截属性的枚举
let target = { a: 1, b: 2 };
let handler = {
ownKeys: function(target) {
return ['a'];
}
};
let proxy = new Proxy(target, handler);
console.log(Object.keys(proxy)); // 输出:['a']
for (let key in proxy) {
console.log(key); // 只会输出:a
}
4:拦截对象的删除操作
let target = { a: 1, b: 2 };
let handler = {
deleteProperty: function(target, prop) {
if (prop === 'a') {
console.log(`Property ${prop} cannot be deleted`);
return false;
}
return true;
}
};
let proxy = new Proxy(target, handler);
console.log(delete proxy.a); // 输出:Property a cannot be deleted,返回 false
console.log(delete proxy.b); // 返回 true
5:撤销代理
let target = {};
let proxy = new Proxy(target, {});
// 撤销代理,revoke 后 proxy 不再可用
let revoke = Proxy.revoke;
revoke(proxy);
// 尝试使用 proxy 将会导致 TypeError
console.log(proxy.foo); // TypeError: Proxy was revoked
6. 拦截函数的调用、 call 和 apply 操作
apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象( this )和目标对象的参数数组。
var handler = {
apply (target, ctx, args) {
return Reflect.apply(...arguments);
}
};
例子
var twice = {
apply (target, ctx, args) {
return Reflect.apply(...arguments) * 2;
}
};
function sum (left, right) {
return left + right;
};
var proxy = new Proxy(sum, twice);
proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30
上面代码中,每当执行 proxy 函数(直接调用或 call 和 apply 调用),就会被 apply 方法拦截。
另外,直接调用 Reflect.apply 方法,也会被拦截。
Reflect.apply(proxy, null, [9, 10]) // 38
7. construct方法用于拦截new命令
//拦截对象的写法
var handler = {
construct (target, args, newTarget) {
return new target(...args);
}
};
var p = new Proxy(function () {}, {
construct: function(target, args) {
console.log('called: ' + args.join(', '));
return { value: args[0] * 10 };
}
});
(new p(1)).value
// "called: 1"
// 10
construct方法返回的必须是一个对象,否则会报错。
var p = new Proxy(function() {}, {
construct: function(target, argumentsList) {
return 1;
}
});
new p() // 报错
// Uncaught TypeError: 'construct' on proxy: trap returned non-object ('1')
标签:ES6,console,target,代理,let,proxy,拦截,Proxy
From: https://blog.csdn.net/qq_35876316/article/details/140259427