我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文通过对类私有属性的读取实验,简单的对比一下proxyreflect在读取类属性时的区别所在。当然,这个对比并不能完全的说明两者的差别,仅仅是个抛砖引玉的效果。

苏南大叔:JavaScript,proxy和reflect读取类私有属性的实践对比 - proxy和reflect读取类私有属性对比
JavaScript,proxy和reflect读取类私有属性的实践对比(图5-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验文章。本文测试环境:win10chrome@116.0.5845.141node@16.14.2

正常读取类私有属性

正如上一篇文章里面,参考:

苏南大叔得出的结论:
正常情况下来说,是不能读取到类的私有属性的。除非对应类主动开放了一个读取私有属性的方法,作为口子。参考代码:

class nan {
  #name = "类真实私有属性";
  get name() {
    console.log("只有类自身内部的方法能访问");
    return this.#name;
  }
}
nan = new nan();
console.log(nan["#name"], nan["name"], nan.name); // undefined 类真实私有属性 类真实私有属性

这里的get name()是本文生效的重要前提。因为私有属性是除了自身外无论如何都不能读取的。所以,必须有个方法将其暴露出去才能读取。

苏南大叔:JavaScript,proxy和reflect读取类私有属性的实践对比 - 私有属性测试代码一
JavaScript,proxy和reflect读取类私有属性的实践对比(图5-2)

reflect读取

下面再使用reflect读取一下试试,测试代码如下:

console.log(Reflect.get(nan,"#name")); // undefined
console.log(Reflect.get(nan,"name"));  // 类真实私有属性

执行结果是:

undefined
类真实私有属性

结论是:reflect和其它的情况一样,无法直接访问私有属性。但是可以通过暴露的get name()拿到数据。

苏南大叔:JavaScript,proxy和reflect读取类私有属性的实践对比 - reflect-get
JavaScript,proxy和reflect读取类私有属性的实践对比(图5-3)

Proxy正常可以调用

这里

su = new Proxy(nan, {
  get(obj, prop, receiver) {
    console.log("代理变量 + obj元素访问 ...");
    return obj[prop];
  },
});
console.log(su["#name"], su["name"], su.name); // undefined 类真实私有属性 类真实私有属性

输出:

代理变量 + obj元素访问  ...

代理变量 + obj元素访问  ...
只有类自身内部的方法能访问

代理变量 + obj元素访问  ...
只有类自身内部的方法能访问

undefined '类真实私有属性' '类真实私有属性'

可见:proxy使用obj[prop]的方式成功拿到了数据。

苏南大叔:JavaScript,proxy和reflect读取类私有属性的实践对比 - proxy-obj-prop
JavaScript,proxy和reflect读取类私有属性的实践对比(图5-4)

在proxy里面使用reflect

常理上来说,在proxy里面使用reflect一点问题都没有。但是,在读取私有属性这件事情上来说,确产生了较大的运行结果差别。测试代码:

da = new Proxy(nan, {
  get(obj, prop, receiver) {
    console.log("代理变量 + Reflect反射访问 ...");
    // return Reflect.get(obj, prop);         // 成功
    // return Reflect.get(obj, prop, obj);   // 成功
    console.log(...arguments)                // 这里的 receiver 是代理本身...
    return Reflect.get(...arguments);        // Cannot read private member #name from an object whose class did not declare it
  },
});
console.log(da["#name"]); // undefined
console.log(da["name"]);  // 主要看`reflect`咋写的了...

proxyget()里面,有三种使用reflect的方法,其最主要的区别是receiver不同。如果对Reflectreceiver传递了proxy默认的receiver,读取私有属性这事就失败了。(但是读取公有属性的事情,是可以的。要不怎么是代理呢?)

苏南大叔:JavaScript,proxy和reflect读取类私有属性的实践对比 - proxy-reflect
JavaScript,proxy和reflect读取类私有属性的实践对比(图5-5)

试图直接使用receiver

da = new Proxy(nan, {
  get(obj, prop, receiver) {
    console.log("代理变量 + Reflect反射访问 ...");
    return receiver[prop];   // 死循环....
  },
});
console.log(da["#name"]); // undefined
console.log(da["name"]);

代码死循环了,吓!

表格对比

proxy里面的get()里面,通过类的公有方法读取私有属性。总结如下:

方法#namename
obj[]undefinedprop
obj.errorprop
proxy[]undefinedprop
proxy.errorprop
Reflect.get(obj,)undefinedprop
proxy.get() + obj[]undefinedprop
proxy.get() + Reflect.get(obj, prop)undefinedprop
proxy.get() + Reflect.get(obj, prop, obj)undefinedprop
proxy.get() + Reflect.get(...arguments)undefinederror
proxy.get() + receiver[]死循环死循环

课后题

下面的代码是官方自带的例子,猜猜看,输出是什么?

class Secret {
  #secret;
  constructor(secret) {
    this.#secret = secret;
  }
  get secret() {
    //  \d+表示1个或多个0到9的数字,是整数部分(至少是一位整数的整数部分)
    return this.#secret.replace(/\d+/, "[REDACTED]");
  }
}
const aSecret = new Secret("文字部分不会被替换,123456");
console.log(aSecret.secret);  //  文字部分不会被替换,[REDACTED]

结束语

从本文的代码上来看,proxyreflect也不是个“水火不容,相互替代”的关系。两者其实也是有合作的可能性的,值得注意的就是proxyreceiver指代的是其代理自身,所以一些情况下,并不适合作为receiver的改写传递到reflect里面。

更多苏南大叔的node经验文章,请点击:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js    node