前言 在 JavaScript 中,ReflectProxy  结合使用实现对对象属性更细粒度的操作控制。
代理对象 Proxy  的第一个参数为要进行代理的目标对象,类型为Object,如果我们代理的目标是一个基础数据类型那应该怎么实现呢?
基础数据类型的代理 在 JavaScript 中,基础数据类型(如 number、string、boolean 等)无法直接被 Proxy 代理 ,因为 Proxy 只能拦截对象(包括数组、函数、类等)的操作。但可以通过对象封装的方式间接代理基础类型:1 2 3 4 5 6 7 8 9 10 11 12 13 const  target  = {    value: '123'   } const  proxy = new  Proxy (target, {    get  (target, key, receiver){                            return  Reflect .get(target, key, receiver)     },     set  (target, key, value, receiver){         return  Reflect .set(target, key, value, receiver)     } }) 
上述代码中有一个疑问,能否通过return target[key] 取代 return Reflect.get(target, key, receiver)? 事实上这里target[key] 等价于 Reflect.get(target, key), receiver是指向代理的实例,相当于call/apply的第一个参数,用于指定函数执行的上下文,上面例子中如果不涉及this指向,仅仅是对于简单类型的代理可使用Reflect.get(target, key) 或 target[key](但不推荐),接下来我们看下面这个例子说明不推荐的原因:
复杂数据类型的代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const  people  = {    get  name(){         console .log('thisArg:' , this )         return  this ._name;     },     _name:'xixi'   }    const  proxy1 = new  Proxy (people, {      get  (target, key, receiver){              console .log('get name:' , target, receiver)       return  Reflect .get(target, key, receiver);      },        })  console .log(proxy1.name)              const  proxy2 = new  Proxy (people, {      get  (target, key, receiver){              console .log('get name:' , target, receiver)       return  target[key];      },  })  console .log(proxy2.name)         
结论:通过对比输出结果,可以看出直接return target[key]会导致this无法绑定在代理对象上,当修改属性时代理事件就无法触发导致错误,所以建议直接按照Reflect.get(target, key, receiver)处理。
响应式编程 此处我们以vue3的响应式编程为例,自定义实现ref和reactive的简化版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 const  targetMap = new  WeakMap ();let  activeEffect = null ;function  effect (fn )   activeEffect = fn;   fn();    activeEffect = null ;  } function  track (target, key )   if  (activeEffect) {     let  depsMap = targetMap.get(target);     if  (!depsMap) {       targetMap.set(target, (depsMap = new  Map ()));     }          let  dep = depsMap.get(key);     if  (!dep) {       depsMap.set(key, (dep = new  Set ()));     }          dep.add(activeEffect);    } } function  trigger (target, key )   const  depsMap = targetMap.get(target);   if  (!depsMap) return ;      const  dep = depsMap.get(key);   if  (dep) {     dep.forEach(effect  =>   } } function  reactive (target )   return  new  Proxy (target, {     get (target, key, receiver) {       const  result = Reflect .get(target, key, receiver);       track(target, key);        return  result;     },     set (target, key, value, receiver) {       const  oldValue = target[key];       const  result = Reflect .set(target, key, value, receiver);       if  (oldValue !== value) {         trigger(target, key);        }       return  result;     }   }); } function  ref (initialValue )   const  _value = { value : initialValue };          if  (typeof  initialValue === 'object'  && initialValue !== null ) {     _value.value = reactive(initialValue);   }      return  new  Proxy (_value, {     get (target, key) {       track(target, key);        return  target[key];     },     set (target, key, value) {              if  (key === 'value'  && typeof  value === 'object'  && value !== null ) {         target[key] = reactive(value);       } else  {         target[key] = value;       }       trigger(target, key);        return  true ;     }   }); }