JavaScript,proxy和reflect读取类私有属性的实践对比
发布于 作者:苏南大叔 来源:程序如此灵动~本文通过对类私有属性的读取实验,简单的对比一下proxy
和reflect
在读取类属性时的区别所在。当然,这个对比并不能完全的说明两者的差别,仅仅是个抛砖引玉的效果。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验文章。本文测试环境:win10
,chrome@116.0.5845.141
,node@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()
是本文生效的重要前提。因为私有属性是除了自身外无论如何都不能读取的。所以,必须有个方法将其暴露出去才能读取。
reflect读取
下面再使用reflect
读取一下试试,测试代码如下:
console.log(Reflect.get(nan,"#name")); // undefined
console.log(Reflect.get(nan,"name")); // 类真实私有属性
执行结果是:
undefined
类真实私有属性
结论是:reflect
和其它的情况一样,无法直接访问私有属性。但是可以通过暴露的get name()
拿到数据。
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]
的方式成功拿到了数据。
在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`咋写的了...
在proxy
的get()
里面,有三种使用reflect
的方法,其最主要的区别是receiver
不同。如果对Reflect
的receiver
传递了proxy
默认的receiver
,读取私有属性这事就失败了。(但是读取公有属性的事情,是可以的。要不怎么是代理呢?)
试图直接使用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()
里面,通过类的公有方法读取私有属性。总结如下:
方法 | #name | name |
---|---|---|
obj[] | undefined | prop |
obj. | error | prop |
proxy[] | undefined | prop |
proxy. | error | prop |
Reflect.get(obj,) | undefined | prop |
proxy.get() + obj[] | undefined | prop |
proxy.get() + Reflect.get(obj, prop) | undefined | prop |
proxy.get() + Reflect.get(obj, prop, obj) | undefined | prop |
proxy.get() + Reflect.get(...arguments) | undefined | error |
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]
结束语
从本文的代码上来看,proxy
和reflect
也不是个水火不容,相互替代的关系。两者其实也是有合作的可能性的,值得注意的就是proxy
的receiver
指代的是其代理自身,所以一些情况下,并不适合作为receiver
的改写传递到reflect
里面。
更多苏南大叔的node
经验文章,请点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。