proxy的局限性

231 阅读2分钟

proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。 const p=new Proxy(target,handler)

handler方法触发时机
handler.getPrototypeOf()Object.getPrototypeOf 方法
handler.setPrototypeOf()Object.setPrototypeOf 方法
handler.isExtensible()Object.isExtensible 方法
handler.preventExtensions()Object.preventExtensions 方法
handler.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor 方法
handler.defineProperty()Object.defineProperty 方法
handler.has()in操作符
handler.get()属性读取操作符
handler.set()属性设置操作符
handler.deleteProperty()delete操作符
handler.ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法
handler.apply()函数调用操作
handler.construct()new 操作符

局限性

内建对象:内部插槽

内建方法可以直接访问内建对象,而不通过[[Get]]/[[Set]]内部方法,所以无法拦截。

let map=new Map()
let proxy=new Proxy(map,{})
proxy.set('test','内建插槽')

image.png 原因是:Map将项目存储在[[MapData]]内部插槽中。代理对象没有这种插槽。Map.prototype.set方法视图访问内部属性this.[[MapData]],但是this=proxy。

私有字段

在 JavaScript 中,私有字段通常是指以双下划线 __ 开头的属性。Proxy 可以拦截对象上的任何操作,包括对私有字段的访问和修改。例如,可以使用 Proxy 拦截对象上的 getset 操作,来实现对私有字段的拦截。

以下是一个使用 Proxy 拦截私有字段的示例:

const obj = {
  __privateField: 'private value'
};

const handler = {
  get(target, prop) {
    if (prop.startsWith('__')) {
      throw new Error('Private field access denied.');
    }
    return target[prop];
  },
  set(target, prop, value) {
    if (prop.startsWith('__')) {
      throw new Error('Private field modification denied.');
    }
    target[prop] = value;
    return true;
  }
};

const proxy = new Proxy(obj, handler);

console.log(proxy.publicField); // undefined
console.log(proxy.__privateField); // 抛出异常:Private field access denied.

proxy.publicField = 'new value';
proxy.__privateField = 'new private value'; // 抛出异常:Private field modification denied.

定义了一个包含私有字段的对象 obj,并使用 Proxy 来拦截对私有字段的访问和修改。在 getset 处理函数中,检查了属性名是否以 __ 开头,如果是,则抛出异常;否则,执行默认操作。这样,就可以实现对私有字段的拦截,从而提高了代码的安全性和可维护性。

兼容问题

如:

  1. IE11 及其以下版本的 Internet Explorer 浏览器不支持 Proxy。
  2. Android 4.4 及其以下版本的 Android 系统不支持 Proxy。
  3. 部分国产手机系统,如华为 EMUI 等,可能会限制某些 ES6 特性的使用,包括 Proxy。

参考资料