ES9 中的 Proxy 对象和 Reflect 对象详解

在前端开发中,经常使用一些 JavaScript 的内置对象,如 ArrayObjectMath 等等。但是 ES9 为我们引入了 Proxy 对象和 Reflect 对象,它们的作用是什么呢?我们来详细了解一下。

Proxy

Proxy 对象是 ES9 新增的一个构造函数,它允许你创建一个代理对象,用来拦截对目标对象的访问和操作。

创建 Proxy

const target = {};
const handler = {
  get: function (obj, prop) {
    console.log(`Getting ${prop} property`);
    return obj[prop];
  },
  set: function (obj, prop, value) {
    console.log(`Setting ${prop} property to "${value}"`);
    obj[prop] = value;
  },
};
const proxy = new Proxy(target, handler);

上面代码中,handler 对象是一个拦截器对象,它定义了 getset 方法用来拦截对 target 对象的读取和设置操作。我们通过 new Proxy 创建了一个代理对象 proxy,当我们利用 proxy 对象操作 target 对象时,会被拦截器对象所拦截,并执行对应的拦截操作。

拦截器方法

Proxy 对象提供了以下的拦截器方法:

  • getPrototypeOf(target) — 在 Object.getPrototypeOf() 中拦截获取对象的原型方法。
  • setPrototypeOf(target, proto) — 在 Object.setPrototypeOf() 中拦截修改对象原型的操作。
  • isExtensible(target) — 在 Object.isExtensible() 中拦截对象是否可以扩展的操作。
  • preventExtensions(target) — 在 Object.preventExtensions() 中拦截阻止对象扩展的操作。
  • get(target, prop, receiver) — 在读取对象属性值时拦截。
  • set(target, prop, value, receiver) — 在设置对象属性值时拦截。
  • has(target, prop) — 对 in 操作符拦截。
  • deleteProperty(target, prop) — 在删除对象属性时拦截。
  • defineProperty(target, prop, descriptor) — 在定义对象属性时拦截。
  • enumerate(target) — 在枚举对象属性时拦截。
  • ownKeys(target) — 拦截 Object.keysObject.getOwnPropertyNamesObject.getOwnPropertySymbols
  • apply(target, thisArg, argumentsList) — 在函数调用时拦截。
  • construct(target, argumentsList, newTarget) — 在使用 new 关键字创建实例对象时拦截。

Proxy 示例

我们通过以下的代码来演示 Proxy 的使用:

const list = [];
const handler = {
  set: function (target, index, value) {
    if (typeof value !== 'number') {
      console.error('Invalid value type');
      return false;
    }

    if (target.length >= index) {
      console.error(`Index ${index} is out of range`);
      return false;
    }

    target[index] = value;
    return true;
  },
};

const proxy = new Proxy(list, handler);
console.log(proxy.length); // 0

proxy[0];
// console.log: Index 0 is out of range
// undefined

proxy[0] = 'invalid value';
// console.log: Invalid value type
// false

proxy[0] = 1.23;
console.log(proxy); // [ 1.23 ]

上面示例中,handler.set 拦截器方法检查了设置到数组的属性值的类型和范围,当条件不符时,会拦截操作并返回 false,反之则将值设置到数组中。

Reflect

Reflect 是 ES9 中的另一个内置对象,它提供一组方法用来操作对象,这些方法与 Proxy 对象拦截器方法的同名方法一样。

Reflect 和 Proxy

  • Proxy 拦截器方法与 Reflect 同名方法一样。
  • Reflect 对象的同名方法可以在 Proxy 拦截器方法中调用,以保持操作的原始行为。

Reflect 示例

通过以下的代码来演示 Reflect 对象的使用:

const apple = { color: 'red' };
console.log(Reflect.get(apple, 'color')); // "red"

Reflect.set(apple, 'color', 'green');
console.log(apple.color); // "green"

Reflect.deleteProperty(apple, 'color');
console.log(apple.color); // undefined

Reflect.defineProperty(apple, 'color', {
  value: 'yellow',
  writable: true,
  configurable: true,
  enumerable: true,
});
console.log(apple.color); // "yellow"

上面的示例中,我们通过 Reflect.getReflect.setReflect.deletePropertyReflect.defineProperty 方法来操作对象 apple

总结

在本文中,我们了解了 ES9 中的 Proxy 和 Reflect 对象。通过 Proxy 对象,我们可以为对象设置拦截器方法,从而拦截读写操作、删除操作等。而 Reflect 对象提供一组方法去操作对象,这些方法可以在 Proxy 对象拦截器方法中被调用。这些对象的使用能够帮助我们解决一些开发中的问题。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65935250eb4cecbf2d8032c0


纠错反馈