ES6+ Proxy与Reflect使用

本文介绍了ES6中Proxy和Reflect的基本用法及实例。详细解释了Proxy如何通过拦截操作来改变默认行为,并展示了Reflect如何提供一致的方式访问对象。通过实际代码演示了get、set等方法的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES6+ Proxy与 Reflect 使用

说明

Proxy 译为 “代理器”,用于修改某些操作的默认行为,可以认为是在目标对象|函数之前架设一层“拦截”,外接的访问,都必须通过这层拦截,这层拦截中可以对外接的访问进行过滤和改写

1. 基本语法

  • target 指被代理的目标对象或函数
  • handler 定制的用来拦截外界操作行为的对象
  • traps 对应外界操作的拦截方法
  • new Proxy() 用来创建一个 proxy 实例
const handler = {
    [traps](...args) {
        ...
    }
};
const obj = new Proxy(target, handler)

2. 支持的拦截操作

  1. get(target, key, receiver) 拦截读取操作
  2. set(target, key, value, receiver) 拦截赋值操作
  3. has(target, key) 拦截 in 操作符操作(for in 循环不算)
  4. deleteProperty(target, key) 拦截 delete 操作符操作
  5. ownKeys(target) 拦截 Object.getOwnPropertyNames(proxy) | Object.getOwnPropertySymbols(proxy) | Object.keys(proxy) 这三个获取键名的操作
  6. getOwnPropertyDescriptor(target, key) 拦截获取属性描述符的操作 Object.getOwnPropertyDescriptor(proxy, key)
  7. defineProperty(target, key, description) 拦截定义属性操作符的操作 Object.defineProperty(proxy, key, description) | Object.defineProperties(proxy, descriptions)
  8. preventExtensions(target) 拦截将对象变为不可扩展的操作 Object.preventExtensions(proxy)
  9. isExtensible(target) 拦截判断对象是否是可扩展的操作 Object.isExtensible(proxy)
  10. getPrototypeOf(target) 拦截返回原型对象的操作,Object.getPrototypeOf(proxy)
  11. apply(target, context, args) 拦截 target 为函数时,调用函数的操作 包括:fn() | fn.call() | fn.apply()
  12. construct(target, args) 拦截以 Proxy 实例为构造函数调用的操作 new Fn()
const def = {
   _def: 'def obj'
};

const proxy = new Proxy(def, {
   // 拦截取值操作
   get(target, key) {
      // get拦截需要有返回值
      return key in target ? target[key] : `target: ${JSON.stringify(target)} Not found key: ${key}`;
   },
   // 拦截赋值操作
   set(target, key, value) {
      if (key === 'age') {
         return console.warn('age is a secret');
      }

      target[key] = value;
   },
   // 拦截 in 操作符操作
   has(target, key) {
      if(key[0] === '_') {
         return false;
      }

      return key in target;
   },
   // 拦截 delete 操作,抛出错误或者返回 false 都无法删除
   deleteProperty(target, key) {
      if (key[0] === '_') {
         console.warn(`Cant delete prop: ${key}`);
         return false;
      }
      console.log('delete', key);
      return true;
   },
   // 拦截 Object.keys() 等获取属性名操作, 返回数组的每一项如果 proxy 中不存在这个属性则会被过滤掉
   ownKeys(target) {
      // proxy 中没有 a 属性所以即使写在返回值中也不会被返回
      return ['a', '_def'];
   }
});

// 取值测试
console.log(proxy.color); // target: {"_def":"def obj"} Not found key: color

// 赋值测试
proxy.age = 90; // age is a secret
proxy.name = '小白';
console.log(JSON.stringify(proxy)); // {"_def":"def obj","name":"小白"}

// in 测试
console.log('_def' in proxy); // false

for (key in proxy) {
   console.log(key); // _def name  has 拦截对 for-in 不生效
}

// delete 测试
delete proxy._def; // Can't delete prop: _def

// Object.keys() 测试
console.log(Object.keys(proxy)); // ["_def"]

/* =========== ============ ============ ============ =========== */

const def = function (a, b) {
   return a * b;
};

const Def = new Proxy(def, {
   // 拦截函数调用
   apply(target, context, args) {
      console.log(context, args, target(...args));
      return target(...args);
   },
   // 拦截构造函数调用
   construct(target, args) {
      if (args.length < 2) {
         console.warn('The arguments is not enough')
         return {value: null};
      }
      return {value: target(...args)};
   }
});

// 测试函数调用

Def(90, 20); // undefined [90, 20] 1800
const ctx = {name: 'ctx'};

Def.call(ctx, 90, 20, 30); // {name: "ctx"} [90, 20, 30] 1800

// 测试构造函数调用
new Def(79); // The arguments is not enough
console.log(new Def(89, 27)); // {value: 2403}

3. Reflect 反射

Reflect 对象的方法与 Proxy 对象的方法一一对应,这样无论在 Proxy 上怎么修改默认行为,都可以通过调用 Reflect 方法来完成默认行为

const def = {
   _def: 'def'
};

const proxy = new Proxy(def, {
   get(target, key) {
      console.log(target, target[key]);
      return Reflect.get(target, key); // 触发默认操作
   }
});

console.log(proxy._def); // def
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值