JavaScript 适用 setters 和 getters 早已很长期了。她们用含有 set 和 get 关键词的简易英语的语法来阻拦目标的特性浏览合值的改动实际操作。
- const obj = {
- propValue: 1,
- get prop() {
- console.log("Retrieving property prop");
- return this.propValue;
- },
- set prop(value) {
- console.log("Setting property prop to", value);
- this.propValue = value;
- }
- };
- obj.prop; // 1 | [in console] Retrieving property prop
- obj.prop = 2; // [in console] Setting property prop to 2
- 1234567891011121314
可是,setter/getter 有好几个缺陷:
- // ...
- Object.defineProperty(obj, "anotherProp", {
- get() {
- /* Do something on get */
- },
- set(value) {
- /*Do something on set */
- }
- });
- 123456789
因而,setter 和 getter 不太合适观查全部目标或实行比较简单的实际操作。因而,ECMAScript 6(ES6)引进了代理商目标(Proxy object)。
代理商是内嵌的 JS 目标,可用以阻拦和变更与目标有关的不一样实际操作的个人行为。
- const originalObj = { prop: 1, anotherProp: "value" };
- const proxyObj = new Proxy(originalObj, {
- get(obj, prop) {
- console.log("Retrieving property", prop);
- return obj[prop];
- },
- set(obj, prop, value) {
- console.log("Setting property", prop, "to", value);
- obj[prop] = value;
- return true;
- }
- });
- originalObj.prop; // 1
- originalObj.prop = 2;
- proxyObj.prop; // 2 | [in console] Retrieving property "prop"
- proxyObj.anotherProp = "new value"; // [in console] Setting property "anotherProp" to "new value"
- 1234567891011121314151617
迅速大家就可以见到 Proxy 与 setter 和 getters 中间的差别。他们不但在英语的语法上各有不同(Proxy 更加冗杂),并且在与初始目标的互动层面也各有不同。Proxy会建立一个新目标供你与之互动,而不是与初始目标开展互动,初始目标在应用 setter/getter 的时候会立即改动。
在应用 Proxy 的状况下,初始目标(也称之为 target)作为一种储存。你对其实行的一切实际操作都是会立即危害代理商,但不容易开启其一切 trap。
代理商的 trap 是实行特殊实际操作时启用的简易方式。他们全是在单独 handler 目标上界定的,随后传送给 Proxy 构造方法。此外,他们不但仅限于 set() 和 get(),还包含一些有意思的实际操作,你能在 MDN 文本文档中寻找。
假如出自于种种原因,你之后想撤销或注销代理商,则应当用静态数据的 Proxy.revocable()方式建立它。
- // ...
- const revocableProxyObj = Proxy.revocable(originalObj, {
- get(obj, prop) {
- /* Do something on get */
- },
- set(obj, prop, value) {
- /*Do something on set */
- }
- });
- const proxy = revocableProxyObj.proxy;
- proxy.prop; // OK
- revocable.revoke();
- proxy.prop // TypeError
- 12345678910111213
该方式并不是立即回到 Proxy 目标,只是回到一个目标,该目标包括坐落于 proxy 特性下的具体 Proxy 和一个额外的 revoke() 方式。
启用时,此方式会使 Proxy 失效,使之后的一切启用均以 TypeError 末尾。以后该代理商将被全自动“废弃物搜集”,进而释放出来存储空间。
与 setter/getter 对比,Proxy 能够使你做大量的事儿。他们更快(申明后)而且更为灵便,使其变成情况管理方法等测试用例的理想化解决方法。
Proxy 产生了许多可订制性,使开发者能够操纵 JS 的一些元作用(meta-functionalities)。因此 他们并并不是向后兼容的,而且沒有一切彻底兼容的 polyfill 的选择项存有。话虽如此,依据 Can I use... 的数据信息,整体的适用看起来非常好,普及率约为 93%(不兼容 IE 和 Safari <10 的版本号)。