代理原对象的 get 方法
// 代理
const target = {
id: "target_id",
name: "target_name",
};
const handler = {
get(origin, property, receiver) {
// 原始对象 (target)
console.log(origin === target);
// 访问的属性
console.log(property);
// 目标对象
console.log(receiver === proxy);
// 原对象的属性 + :proxy
return origin[property] + ":proxy";
},
};
const proxy = new Proxy(target, handler);
// 访问属性时回出发 get() 方法
console.log(proxy.name);
捕获器不变式
不可以对只读属性设置代理
// 代理
const target = {};
// 把 name 属性设置只读
Object.defineProperty(target, "name", {
configurable: false,
writable: false,
value: "张三",
});
const handler = {
get(origin, property, receiver) {
return origin[property] + ":proxy";
},
};
const proxy = new Proxy(target, handler);
// 报错: 无法通过代理改变原始对象的 name 属性值
console.log(proxy.name);
// TypeError: 'get' on proxy: property 'name' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '张三' but got '张三:proxy')
可撤销代理
const target = {
id: "target_id",
name: "target_name",
};
const handler = {
get(origin, property, receiver) {
return origin[property] + ":proxy";
},
};
// 创建一个可撤销对象
const { proxy, revoke } = Proxy.revocable(target, handler);
console.log(proxy.name);
// 断开代理
revoke();
// 报错:TypeError: Cannot perform 'get' on a proxy that has been revoked
console.log(proxy.name);
十三种捕获器
1. get()
2. set()
// set 捕获器
const target = {};
const proxy = new Proxy(target, {
// 必须返回布尔值,返回非布尔值会被转义成布尔
set(origin, property, value, receiver) {
console.log("set()");
return Reflect.set(...arguments);
},
});
proxy.name = "bar";
3. has 捕获器
const proxy1 = new Proxy(target, {
// 必须返回布尔值,返回非布尔值会被转义成布尔
has(origin, property) {
console.log("has()");
return Reflect.has(...arguments);
},
});
"name" in proxy1;
4. defineProperty() 捕获器
const proxy2 = new Proxy(target, {
// 必须返回布尔值,返回非布尔值会被转义成布尔
defineProperty(origin, property, descriptor) {
console.log("defineProperty()");
return Reflect.defineProperty(...arguments);
},
});
console.log(Object.defineProperty(proxy2, "name", { value: "张三" }));
5. getOwnPropertyDescriptor
const proxy3 = new Proxy(target, {
getOwnPropertyDescriptor(origin, property) {
console.log("getOwnPropertyDescriptor()");
return Reflect.getOwnPropertyDescriptor(...arguments);
},
});
console.log(Object.getOwnPropertyDescriptor(proxy3, "name"));
6. deleteProperty()
const proxy4 = new Proxy(target, {
deleteProperty(origin, property) {
console.log("deleteProperty()");
return Reflect.deleteProperty(...arguments);
},
});
console.log(delete proxy4.name);
7. ownKeys()
8. getPrototypeOf()
9. setPrototypeOf()
10. isExtensible()
11. preventExtensions()
12. apply()
13. construct()
常见代理使用场景
跟踪属性访问
通过捕获get、set和has等操作,可以知道对象属性什么时候被访问、被查询。把实现相应捕获器的某个对象代理放到应用中,可以监控这个对象何时在何处被访问
const user = {
name: "jake",
};
const proxy = new Proxy(user, {
get(origin, property, receiver) {
console.log(`get ${property}`);
return Reflect.get(...arguments);
},
set(origin, property, value, receiver) {
console.log(`set ${property} = ${value}`);
return Reflect.set(...arguments);
},
});
proxy.name;
proxy.name = "dc";
隐藏属性
const hiddenAttr = ["name", "idCard"];
const user = {
name: "dc",
idCard: "kjhadskfa",
age: 10,
sex: 1,
};
const proxy = new Proxy(user, {
get(origin, property, receiver) {
if (hiddenAttr.includes(property)) {
return `${property} 不可访问`;
}
return Reflect.get(...arguments);
},
});
// name 不可访问
console.log(proxy.name);
属性验证
检验值是否合法
user = {};
proxy = new Proxy(user, {
set(origin, property, value, receiver) {
if (typeof value !== "number") {
console.log("非法类型");
return false;
}
return Reflect.set(...arguments);
},
});
proxy.age = 1;
proxy.age = "2";
console.log(proxy.age);
构造函数参数验证
class User {
constructor(id) {
this._id = id;
}
}
const UserProxy = new Proxy(User, {
construct(origin, args, newTarget) {
if (args[0] === undefined || args[0] === null) {
throw "id 不能为空";
}
console.log(args);
return Reflect.construct(...arguments);
},
});
new UserProxy(1);
new UserProxy(null);
数据绑定
一个数据发生变化,另外一个同步变化
const userList = [];
function addEvent(newValue) {
console.log(newValue);
}
const proxy = new Proxy(userList, {
set(origin, property, value, receiver) {
const result = Reflect.set(...arguments);
if (result) {
addEvent(value);
}
return result;
},
});
proxy.push("张三");
联系方式:dccmmtop@foxmail.com