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

本文要讨论的内容非常有趣,是JavaScript中一个叫做proxy的功能,苏南大叔翻译为“代理”。它可以代理一个Object或一个Class,或者说某些普通变量。然后,就可以一方面有对应变量做后盾,另一方面又可以根据实际情况,做一定的修改。react或者vue们,背后的变量监控原理都有proxy的身影。

苏南大叔:JavaScript,如何利用proxy代理一个对象obj,改写其属性? - js-proxy-set-get
JavaScript,如何利用proxy代理一个对象obj,改写其属性?(图4-1)

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的编程经验体会。测试环境:win10chrome。在node@18.14.2下,部分代码也可以顺利运行。本文中的proxy并不是常说的那个浏览器代理,不要混淆概念!!!

前文回顾

这些可以改写其它代码或变量的代码,用起来都会非常有趣。苏南大叔也写过类似文章,可以查看:

测试基础数据

本文的内容,是基于下面的数据定义的。

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);

苏南大叔:JavaScript,如何利用proxy代理一个对象obj,改写其属性? - proxy基础变量
JavaScript,如何利用proxy代理一个对象obj,改写其属性?(图4-2)

一共定义了三个变量,

  • 第一个是原始变量sn,有两个属性hito。[注意:这个变量是个const常量,但是能被改写]
  • 第二个是改写规则handler,可以改写setget
  • 第三个是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);   // 苏南大叔

苏南大叔:JavaScript,如何利用proxy代理一个对象obj,改写其属性? - pxoxy附加代码
JavaScript,如何利用proxy代理一个对象obj,改写其属性?(图4-3)

proxy改写set逻辑(合理性验证逻辑)

这里用当下最流行的买盐为例,5袋限购,这里设置属性salt。当数量设置超过5的时候,会引发错误提示。

// 代理变量输出
ssnn.salt = 1;
console.log("买了几袋盐?", ssnn.salt,sn.salt);    // 买了几袋盐? 1 1
ssnn.salt = 10;                                   // 抛出错误
注意:这个属性salt被透传回去了。

苏南大叔:JavaScript,如何利用proxy代理一个对象obj,改写其属性? - proxy运算结果
JavaScript,如何利用proxy代理一个对象obj,改写其属性?(图4-4)

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的应用还有很多,这里就先抛砖引玉,先写最简单的getset的功能。

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

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

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

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