Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。属于“元编程”,即对编程语言进行编程。
如对对象a进行拦截就 let p = new Proxy(obj,handler)在handler里面编写拦截逻辑;
又如有对象a和b,想要对对象a中实现拦截对象b的属性,就将对象b设置到对象a的原型上再编写拦截逻辑;
const p = new Proxy(target, handler)
const { proxy: p, revoke } = Proxy.revocable(data, handler)
let obj = { a:1 };
let handler = {
get(target, property, receiver){
console.log(this);
return target[property];//get中需要返回对应属性
}
};
let p = new Proxy(obj,handler);
console.log(p.a);//注意要通过代理对象获取才能触发 get拦截
IsRevoked:当前属性是否被撤销。const { proxy: p, revoke } = Proxy.revocable(data, handler)创建一个可撤销的代理对象
通过const { proxy: p, revoke } = Proxy.revocable(data, handler)创建可被撤销的对象实例后,此时IsRevoked为false,p.a 去调用属性会返回;
当在调用revoke();方法用于撤销代理对象,调用后IsRevoked为true,p.a 去调用属性会报错;
let obj = { a:1 };
let handler = {};
const { proxy, revoke } = Proxy.revocable(obj, handler);
var p = new Proxy(target, {
get (target, property, receiver) {
}
})
let obj = { a: 1, b: 2 };
let handler = {
get(target, property, receiver) {
console.log(target, property, receiver);
return target[property];
}
};
let proxy = new Proxy(obj, handler);
console.log(proxy.a);
这里的问题是代理对象proxy.name想要获取到的是obj1上的name。
比如,使用Proxy代理对象obj2,并将proxy实例对象设置到obj1的原型上,则通过obj1就可以获取到Proxy代理后的obj2的属性。此时通过proxy.name就可以获取到obj2的属性name值"lmf"
let obj1 = { a: 1, b: 2, name: 'allen' };
let obj2 = {
name: 'lmf',
get value() {
return this.name
}
}
let handler = {
get(target, property, receiver) {
return target[property];
// return Reflect.get(target, property, receiver);
}
};
let proxy = new Proxy(obj2, handler);
// 将obj2的属性设置到obj1的原型上,则通过obj1就可以获取到obj2的属性
Object.setPrototypeOf(obj1, proxy);
console.log(obj1);
console.log(obj1.value);//lmf
其实这里obj1.name应该为allen才对,可以通过return Reflect.get(target, property, receiver);设置,类似与改变this指向为目标对象target也就是obj1
let obj1 = { a: 1, b: 2, name: 'allen' };
let obj2 = {
name: 'lmf',
get value() {
return this.name
}
}
let handler = {
get(target, property, receiver) {
return Reflect.get(target, property, receiver);
}
};
let proxy = new Proxy(obj2, handler);
// 将obj2的属性设置到obj1的原型上,则通过obj1就可以获取到obj2的属性
Object.setPrototypeOf(obj1, proxy);
console.log(obj1);
console.log(obj1.value);//lmf
// 访问原型链上的属性:Object.create(proxy)[foo]
let obj1 = { foo:'foo' };
let handler = {
get(target, property, receiver) {
console.log("触发了");
return target[property]
}
};
let proxy = new Proxy(obj1, handler);
const p = Object.create(proxy);
console.log(p['foo']);
// Reflect.get()访问属性
let obj1 = { foo: 'foo' };
let handler = {
get(target, property, receiver) {
console.log("触发了");
return target[property]
}
};
let proxy = new Proxy(obj1, handler);
Reflect.get(proxy, 'foo')
handler.set() 方法是设置属性值操作的捕获器。
const p = new Proxy(target, {
set: function(target, property, value, receiver) {
}
});
该方法会拦截目标对象的以下操作
1. 指定属性值:proxy[foo] = bar 和 proxy.foo = bar
2. 指定继承者的属性值:Object.create(proxy)[foo] = bar
3. Reflect.set()
let obj1 = {
myTime : "1697683657936"
}
let handler = {
set(target, property, value){
let setTime = value + new Date().getTime();
target[property] = setTime;
}
}
let proxy = new Proxy(obj1,handler);
proxy.myTime = "此时的时间戳是:";
console.log(proxy.myTime);
需要实现的功能
1. 验证age属性的数据类型是否为整数
2. 验证值的范围是否小于等于200
// 需要实现的功能
// 1. 验证age属性的数据类型是否为整数
// 2. 验证值的范围是否小于等于200
let user = {
age: 100
}
let handler = {
set(target,property,value){
if(property==='age'){
if(!Number.isInteger(value)){
throw new TypeError("age的值必须是整数");
}
if(value>200){
throw new RangeError("age的值不能超过200");
}
}
}
}
let proxy = new Proxy(user,handler);
// proxy.age = 22.3;
proxy.age = 300
需要实现的功能
var data = [
{ name: 'Firefox' , type: 'browser' },
{ name: 'SeaMonkey' , type: 'browser' },
{ name: 'Thunderbird', type: 'mailer' }
]
1. 通过索引返回对应数据 proxy[0]
2. 通过number属性返回数组长度 proxy.number
3. 通过name获取对应的数据 proxy['Firefox']
4. 通过type返回对应的数据 proxy['browser']
5. 通过types返回data中的type products.types
var data = [
{ name: 'Firefox', type: 'browser' },
{ name: 'SeaMonkey', type: 'browser' },
{ name: 'Thunderbird', type: 'mailer' }
]
let handler = {
get(target, property) {
// 2. 通过number属性返回数组长度 proxy.number
if (property === 'number') {
return target.length;
}
let result = [];
target.forEach((item, index) => {
// 1. 通过索引返回对应数据 proxy[0]
if (property == index) {
return result.push(item);
}
// 3. 通过name获取对应的数据 proxy['Firefox']
if (property === item.name) {
return result.push(item);
}
// 4. 通过type返回对应的数据 proxy['browser']
if (property === item.type) {
return result.push(item);
}
// 5. 通过types返回data中的type products.types
if (property === 'types') {
result.push(item.type);
result = [...new Set(result)]
}
});
return result;
}
}
let proxy = new Proxy(data, handler);
console.log(proxy[0]);
console.log(proxy.number);
console.log(proxy['Firefox']);
console.log(proxy['browser']);
console.log(proxy['types']);