这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
前言
hello,大家好,今天还是复习ES6的一天,今天复习的时候,总结一波大家可能没有覆盖的代理小知识点,今天我们就来谈一谈吧。
代理另一个代理
代理可以拦截反射 API 的操作,而这意味着完全可以创建一个代理,通过它去代理另一个代理。这样就可以在一个目标对象之上构建多层拦截网:
const target ={
foo :' bar ' (
);
constfirstProxy = new Proxy ( target ,{
get (){
console . log (' first proxy ');
return Reflect . get (... arguments );
));
const secondProxy = new Proxy ( firstProxy ,{
get (){
console . log (' second proxy ');
return Reflect . get (... arguments );
});
console . log ( secondProxy . foo );
// second proxy
/ first proxy
代理的问题与不足
代理是在 ECMAScript 现有基础之上构建起来的一套新 API ,因此其实现已经尽力做到最好了。很大程度上,代理作为对象的虚拟层可以正常使用。但在某些情况下,代理也不能与现在的 ECMAScript 机制很好地协同。\
1.代理中的 this
代理潜在的一个问题来源是 this 值。我们知道,方法中的 this 通常指向调用这个方法的对象
const target ={
thisValEqualsProxy (){ return this === proxy ;
const proxy = new Proxy ( target ,{0);
console . log ( target . thisValEqualsProxy ());// false
console .1og( proxy . thisValEqualsProxy ());// true
}
这样完全没有问题:调用代理上的任何方法,比如 proxy . outerMethod (),而这个方法进而又会调用另一个方法,如 this . innerMethod (),实际上都会调用 proxy . innerMethod ()。多数情况下,这是符合预期的行为。可是,如果目标对象依赖于对象标识,那就可能碰到意料之外的问题。 还记得第6章中通过 WeakMap 保存私有变量的例子吧,以下是它的简化版:
class User {\
constructor ( userId ){
Wm . set ( thiS , userId );
set id ( userId ){
wm . set ( this , userId );
getid (){
return wm . get ( this );
}
由于这个实现依赖 User 实例的对象标识,在这个实例被代理的情况下就会出问题:
const user = new User (123);
console . log ( user . id );//123
const userInstanceProxy = new Proxy ( user ,{});
console . log ( userInstanceProxy . id );// undefined
这是因为 User 实例一开始使用目标对象作为 WeakMap 的键,代理对象却尝试从自身取得这个实例。要解决这个问题,就需要重新配置代理,把代理 User 实例改为代理 User 类本身。之后再创建代理的实例就会以代理实例作为 WeakMap 的键了:
const UserClassProxy = new Proxy ( User ,(0);
const proxyUser = new UserClassProxy (456); console . log ( proxyUser . id );
2.代理与内部槽位
代理与内置引用类型(比如 Array )的实例通常可以很好地协同,但有些 ECMAScript 内置类型可 能会依赖代理无法控制的机制,结果导致在代理上调用某些方法会出错。 一个典型的例子就是 Date 类型。根据 ECMAScript 规范, Date 类型方法的执行依赖 this 值上的内部槽位[[ NumberDate ]]。代理对象上不存在这个内部槽位,而且这个内部槽位的值也不通过普通的 get (和 set (操作访问到,于是代理拦截后本应转发给目标对象的方法会抛出 TypeError :
consttarget = neWDate ();
Const prOxy = neWPrOxy ( target ,{});
console . log ( proxy instanceof Date );// true
proxy - getDate ();// TypeError :' this ' is not a Date object