首页ES6 Proxy的API介绍及应用场景
Created At : 2021-11-19

# ES6 Proxy的API介绍及应用场景

Proxy的语法非常简单,所有的Proxy示例都是基于以下语法:

/***
* target
* 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
* handler
* 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
* p
* Proxy的实例
*/
const p = new Proxy(target, handler)

基础示例

基于以上语法先创建一个示例:

//1: 定义一个target,名称随意,如 person
const person = {
  name: 'Jack'
};
//2:创建一个handler,名称随意,这里就叫handler
const handler = {
  //trap,提供属性访问的方法
  get(target, property) {
    console.log(`正在读取属性: ${property}`);
    return "Jack Ma"
  }
};
//3: 通过构造函数创建一个Proxy实例proxyPerson
const proxyPerson = new Proxy(person, handler);
console.log(proxyPerson.name); //Jack Ma
console.log(person.name);  //Jack, 针对target对象本身操作,没有任何效果

//------------------------------结果如下:
正在读取属性: name
Jack Ma
Jack

从以上示例可知:

  • 要使得Proxy起作用,必须针对Proxy实例(上例是proxyPerson对象)进行操作,而不是针对目标对象(person)进行操作
  • Proxy实例对象代理了person的所有属性。
  • 对Proxy实例对象的读操作(proxyPerson.name),会被handler中的get进行监听和拦截,并可以改变其值,如本例,将Jack改为Jack Ma

1.get() Trap

当访问指定属性时触发,例如上面的基础示例。

//拦截对象属性的读取,比如proxy.foo和proxy['foo']
get(target, propKey, receiver)

get() trap应用示例1:创建私有属性

通常作为约定,以_开头的变量为对象的私有属性,不能访问,但是在JavaScript中,这只是开发上约束,并不能阻止用户真正的访问。

比如:

const person = {
    dateOfBirth: '2003-11-11',
 	 //_age属性为私有属性,其值应该通过dateOfBirth进行计算
    _age: 18
}
person._age  //用户还是可以访问

但是,通过get() trap我们可以实现阻止用户对私有属性的读取或赋值操作:

const person = {
  dateOfBirth: '2003-11-11',
  //_age属性为私有属性,其值应该通过dateOfBirth进行计算
  _age: 18
}

const handler = {
  get: function(target, key) {
    if (key[0] === '_') {
      throw new Error('Attempt to access private property');
    }
    return target[key];
  },
  set: function(target, key, value) {
    if (key[0] === '_') {
      throw new Error('Attempt to access private property');
    }
    target[key] = value;
  }
};

const p = new Proxy(person,handler)

//访问_age,会抛出异常, 同样,为其赋值也会抛出异常。
//Error: Attempt to access private property
p._age 

2.set() Trap

用法同get,不过是在赋值是触发。例如上例中的 p._age = 18

//拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
//target: The target object that the proxy attached to
//property: The name of the property being set
//value: The value which is assigned to the property
set(target, propKey, value, receiver)

应用示例:

const person = {
  score: 60
}

const handler = {
  set: function(target, key, value) {
    if (key === 'score') {
      if (!(typeof value === 'number')) {
        throw new Error('分数应该是数字');
      }

      if (value < 0 || value > 150) {
        throw new Error("分数不能低于0或高于150");
      }
    }
    console.log("当前分数为:",value)
    target[key] = value;
  }
};

const p = new Proxy(person,handler)

p.score = 100  // OK,当前分数为: 100
p.score = 200  // throw new Error,Error: 分数不能低于0或高于150

3.has() trap

4.deleteProperty() trap

5.ownKeys() trap

6.getOwnPropertyDescriptor() trap

7.defineProperty() trap

8.preventExtensions() trap

9.getPrototypeOf() trap

10.isExtensible() trap

11.setPrototypeOf() trap

12.apply() trap

13.construct() trap