JavaScript 的代理对象

前端 2023-07-05 17:29:38
42阅读

JavaScript 适用 setters 和 getters 早已很长期了。她们用含有 set 和 get 关键词的简易英语的语法来阻拦目标的特性浏览合值的改动实际操作。

 
  1. const obj = { 
  2.   propValue: 1, 
  3.   get prop() { 
  4.     console.log("Retrieving property prop"); 
  5.     return this.propValue; 
  6.   }, 
  7.   set prop(value) { 
  8.     console.log("Setting property prop to", value); 
  9.     this.propValue = value
  10.   } 
  11. }; 
  12.  
  13. obj.prop; // 1 | [in console] Retrieving  property prop 
  14. obj.prop = 2; // [in console] Setting property prop to 2 
  15.  
  16. 1234567891011121314 

可是,setter/getter 有好几个缺陷:

  • 他们只限 get 和 get 实际操作(显而易见)。
  • 他们不可以与同样键(即“基本”特性)的数据信息通道一起应用。
  • 他们并不是动态性的,务必在目标申明期内用静态数据的 Object.defineProperty() 方式或根据应用测算值(仅适用新的电脑浏览器)显式地运用于每一个特性。
 
  1. // ... 
  2. Object.defineProperty(obj, "anotherProp", { 
  3.   get() { 
  4.     /* Do something on get */ 
  5.   }, 
  6.   set(value) { 
  7.     /*Do something on set */ 
  8.   } 
  9. }); 
  10.  
  11. 123456789 

因而,setter 和 getter 不太合适观查全部目标或实行比较简单的实际操作。因而,ECMAScript 6(ES6)引进了代理商目标(Proxy object)。

代理商(Proxy)

代理商是内嵌的 JS 目标,可用以阻拦和变更与目标有关的不一样实际操作的个人行为。

 
  1. const originalObj = { prop: 1, anotherProp: "value" }; 
  2. const proxyObj = new Proxy(originalObj, { 
  3.   get(obj, prop) { 
  4.     console.log("Retrieving property", prop); 
  5.     return obj[prop]; 
  6.   }, 
  7.   set(obj, prop, value) { 
  8.     console.log("Setting property", prop, "to", value); 
  9.     obj[prop] = value; 
  10.     return true; 
  11.   } 
  12. }); 
  13. originalObj.prop; // 1 
  14. originalObj.prop = 2
  15.  
  16. proxyObj.prop; // 2 | [in console] Retrieving property "prop" 
  17. proxyObj.anotherProp = "new value"; // [in console] Setting property "anotherProp" to "new value" 
  18.  
  19. 1234567891011121314151617 

迅速大家就可以见到 Proxy 与 setter 和 getters 中间的差别。他们不但在英语的语法上各有不同(Proxy 更加冗杂),并且在与初始目标的互动层面也各有不同。Proxy会建立一个新目标供你与之互动,而不是与初始目标开展互动,初始目标在应用 setter/getter 的时候会立即改动。

在应用 Proxy 的状况下,初始目标(也称之为 target)作为一种储存。你对其实行的一切实际操作都是会立即危害代理商,但不容易开启其一切 trap。

代理商的 trap 是实行特殊实际操作时启用的简易方式。他们全是在单独 handler 目标上界定的,随后传送给 Proxy 构造方法。此外,他们不但仅限于 set() 和 get(),还包含一些有意思的实际操作,你能在 MDN 文本文档中寻找。

可撤消代理商

假如出自于种种原因,你之后想撤销或注销代理商,则应当用静态数据的 Proxy.revocable()方式建立它。

 
  1. // ... 
  2. const revocableProxyObj = Proxy.revocable(originalObj, { 
  3.   get(obj, prop) { 
  4.     /* Do something on get */ 
  5.   }, 
  6.   set(obj, prop, value) { 
  7.     /*Do something on set */ 
  8.   } 
  9. }); 
  10. const proxy = revocableProxyObj.proxy; 
  11. proxy.prop; // OK 
  12. revocable.revoke(); 
  13. proxy.prop // TypeError 
  14.  
  15. 12345678910111213 

该方式并不是立即回到 Proxy 目标,只是回到一个目标,该目标包括坐落于 proxy 特性下的具体 Proxy 和一个额外的 revoke() 方式。

启用时,此方式会使 Proxy 失效,使之后的一切启用均以 TypeError 末尾。以后该代理商将被全自动“废弃物搜集”,进而释放出来存储空间。

测试用例

与 setter/getter 对比,Proxy 能够使你做大量的事儿。他们更快(申明后)而且更为灵便,使其变成情况管理方法等测试用例的理想化解决方法。

Proxy 产生了许多可订制性,使开发者能够操纵 JS 的一些元作用(meta-functionalities)。因此 他们并并不是向后兼容的,而且沒有一切彻底兼容的 polyfill 的选择项存有。话虽如此,依据 Can I use... 的数据信息,整体的适用看起来非常好,普及率约为 93%(不兼容 IE 和 Safari <10 的版本号)。

the end
免责声明:本文不代表本站的观点和立场,如有侵权请联系本站删除!本站仅提供信息存储空间服务。