JavaScript,如何利用proxy代理一个对象obj,改写其属性?
发布于 作者:苏南大叔 来源:程序如此灵动~ 我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...
本文要讨论的内容非常有趣,是JavaScript
中一个叫做proxy
的功能,苏南大叔翻译为“代理”。它可以代理一个Object
或一个Class
,或者说某些普通变量。然后,就可以一方面有对应变量做后盾,另一方面又可以根据实际情况,做一定的修改。react
或者vue
们,背后的变量监控原理都有proxy
的身影。
苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的编程经验体会。测试环境:win10
,chrome
。在node@18.14.2
下,部分代码也可以顺利运行。本文中的proxy
并不是常说的那个浏览器代理,不要混淆概念!!!
前文回顾
这些可以改写其它代码或变量的代码,用起来都会非常有趣。苏南大叔也写过类似文章,可以查看:
- https://newsn.net/say/js-hook.html
- https://newsn.net/say/js-object-set-get.html
- https://newsn.net/say/js-object-writable.html
- https://newsn.net/say/php-extension-evalhook.html
- https://newsn.net/say/python-decorators.html
测试基础数据
本文的内容,是基于下面的数据定义的。
const sn = {
hi: "hello",
to: "苏南大叔",
};
const handler = {
get(obj, prop, receiver) {
if (prop in obj) {
if (prop === "hi") {
// 这里做了拦截
return "hola";
}
return obj[prop];
}
return "无此属性";
},
set(obj, prop, value) {
if (prop === "salt") {
value = parseInt(value);
if (value > 5) {
// 这里做了合法性验证
throw new RangeError(`[${value}]超出限购数5`);
}
}
obj[prop] = value;
return true;
},
};
const ssnn = new Proxy(sn, handler);
一共定义了三个变量,
- 第一个是原始变量
sn
,有两个属性hi
和to
。[注意:这个变量是个const
常量,但是能被改写] - 第二个是改写规则
handler
,可以改写set
和get
。 - 第三个是
new Prxoy()
的返回值ssnn
了,就是本文的龙套主角。
proxy改写get逻辑
对于一个object的属性读写,大家都知道:背后都调用了get()
或者set()
等系统函数。那么,proxy
的重要功能就是能对这种属性读写的函数下钩子。测试代码:
// 代理变量输出
console.log(ssnn.hi); // hola
console.log(ssnn.to); // 苏南大叔
这种proxy
通过set
或者get
方式拦截属性的写法,不影响原object
的固有属性。测试代码:
// 原版变量输出
console.log(sn.hi); // hello
console.log(sn.to); // 苏南大叔
proxy改写set逻辑(合理性验证逻辑)
这里用当下最流行的买盐为例,5袋限购,这里设置属性salt
。当数量设置超过5的时候,会引发错误提示。
// 代理变量输出
ssnn.salt = 1;
console.log("买了几袋盐?", ssnn.salt,sn.salt); // 买了几袋盐? 1 1
ssnn.salt = 10; // 抛出错误
注意:这个属性salt
被透传回去了。
proxy可透传属性【相当实用】
如果变量没有被handler
拦截的话,无论是否是新属性,都可以被透传回原变量的。
上述hi
属性没有被改变的原因是:被handler
里面的get
方法拦截了。
// ssnn 是代理变量,sn 是原版变量
ssnn.www = "newsn.net";
console.log(ssnn.www); // newsn.net
console.log(sn.www); // newsn.net
console.log(ssnn.ww); // 无此属性
console.log(sn.ww); // undefined
实际上还可以透传新方法到原对象,本文暂时不做讨论,期待后续文章。
参考文章
主要参考的是官方的例子:
结束语
本文结论:属性如果没有被handler
拦截的情况下,无论原本是否存在,都可以透传回去。关于proxy
的应用还有很多,这里就先抛砖引玉,先写最简单的get
和set
的功能。
如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。