JS的Proxy

Proxy

概念

一个 Proxy 对象包装另一个对象并拦截诸如读取/写入属性和其他操作,可以选择自行处理它们,或者透明地允许该对象处理它们。

Proxy 被用于了许多库和某些浏览器框架。在本文中,我们将看到许多实际应用。

语法

let proxy = new Proxy(target, handler)

参数

  • target —— 是要包装的对象,可以是任何东西,包括函数。

  • handler —— 代理配置:带有“捕捉器”(“traps”,即拦截操作的方法)的对象。比如 get 捕捉器用于读取 target 的属性,set 捕捉器用于写入 target 的属性,等等。

    proxy 进行操作,如果在 handler 中存在相应的捕捉器,则它将运行,并且 Proxy 有机会对其进行处理,否则将直接对 target 进行处理。

例子

let target = {};
let proxy = new Proxy(target, {}); // 空的 handler 对象

proxy.test = 5; // 写入 proxy 对象 (1)
alert(target.test); // 5,test 属性出现在了 target 中!

alert(proxy.test); // 5,我们也可以从 proxy 对象读取它 (2)

for(let key in proxy) alert(key); // test,迭代也正常工作 (3)

由于没有捕捉器,所有对 proxy 的操作都直接转发给了 target

  1. 写入操作 proxy.test= 会将值写入 target
  2. 读取操作 proxy.test 会从 target 返回对应的值。
  3. 迭代 proxy 会从 target 返回对应的值。

我们可以看到,没有任何捕捉器,proxy 是一个 target 的透明包装器(wrapper)。

在这里插入图片描述

常用的捕捉器

get

要拦截读取操作,handler 应该有 get(target, property, receiver) 方法。

参数

  • target —— 是目标对象,该对象被作为第一个参数传递给 new Proxy
  • property —— 目标属性名,
  • receiver —— 如果目标属性是一个 getter 访问器属性,则 receiver 就是本次读取属性所在的 this 对象。通常,这就是 proxy 对象本身(或者,如果我们从 proxy 继承,则是从该 proxy 继承的对象)。

例子:

let numbers = [0, 1, 2];

numbers = new Proxy(numbers, {
  get(target, prop) {
    if (prop in target) {
      return target[prop];
    } else {
      return 0; // 默认值
    }
  }
});

alert( numbers[1] ); // 1 注意如果numbers = [0, 2, 1]则结果为2.因为返回的是target[prop]
alert( numbers[123] ); // 0(没有这个数组项)

注意

代理应该在所有地方都完全替代目标对象。目标对象被代理后,任何人都不应该再引用目标对象。否则很容易搞砸。

set

假设我们想要一个专门用于数字的数组。如果添加了其他类型的值,则应该抛出一个错误。

当写入属性时 set 捕捉器被触发。

set(target, property, value, receiver)

参数

  • target —— 是目标对象,该对象被作为第一个参数传递给 new Proxy
  • property —— 目标属性名称,
  • value —— 目标属性的值,
  • receiver —— 与 get 捕捉器类似,仅与 setter 访问器属性相关。

例子

let numbers = [];

numbers = new Proxy(numbers, { // (*)
  set(target, prop, val) { // 拦截写入属性操作
    if (typeof val == 'number') {
      target[prop] = val;
      return true;
    } else {
      return false;
    }
  }
});

numbers.push(1); // 添加成功
numbers.push(2); // 添加成功
alert("Length is: " + numbers.length); // 2

numbers.push("test"); // TypeError(proxy 的 'set' 返回 false)

alert("This line is never reached (error in the line above)");

别忘了返回 true

对于 set 操作,它必须在成功写入时返回 true

其他捕捉器

内部方法Handler 方法何时触发
[[Get]]get读取属性
[[Set]]set写入属性
[[HasProperty]]hasin 操作符
[[Delete]]deletePropertydelete 操作符
[[Call]]apply函数调用
[[Construct]]constructnew 操作符
[[GetPrototypeOf]]getPrototypeOfObject.getPrototypeOf
[[SetPrototypeOf]]setPrototypeOfObject.setPrototypeOf
[[IsExtensible]]isExtensibleObject.isExtensible
[[PreventExtensions]]preventExtensionsObject.preventExtensions
[[DefineOwnProperty]]definePropertyObject.defineProperty, Object.defineProperties
[[GetOwnProperty]]getOwnPropertyDescriptorObject.getOwnPropertyDescriptor, for..in, Object.keys/values/entries
[[OwnPropertyKeys]]ownKeysObject.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in, Object.keys/values/entries
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值