ES6的代理模式

语法

1
const proxy = new Proxy(target, handle)
  • target: 使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理
  • handle: 一个通常以函数作为属性的对象,用来定制拦截行为
1
2
3
4
5
6
7
8
9
// 例子
let obj = {}
let proxyObj = new Proxy(obj, {
get: function(target, propKey, receiver) {
return '6'
}
})
proxyObj.a // '6'
obj.a // undefined

代理只会对proxy对象生效,原对象没有效果。

Handler 对象常用的方法

  • has: in 操作符的捕捉器。
  • get: 属性读取操作的捕捉器
  • set: 属性读取操作的捕捉器
  • deleteProperty: delete 操作符的捕捉器
  • ownKeys: Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。
  • apply: 函数调用操作的捕捉器。
  • construct: new 操作符的捕捉器

hander.get

用于代理目标对象的属性读取操作, 授受三个参数 get(target, propKey, ?receiver)

  • target 目标对象

  • propkey 属性名

  • receiver Proxy 实例本身

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const person = {
    like: "sing dance rap basketball"
    }

    const obj = new Proxy(person, {
    get: function(target, propKey) {
    if (propKey in target) {
    return target[propKey];
    } else {
    throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
    }
    }
    })
    obj.like // sing dance rap basketball
    obj.cxk // Uncaught ReferenceError: Prop name "cxk" does not exist.
    // 在读取代理目标的值时,如果有值则直接返回,没有值就抛出一个自定义的错误

    注意:

    • 如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同
    • 如果要访问的目标属性没有配置访问方法,即get方法是undefined的,则返回值必须为undefined

可撤消的Proxy

proxy 有一个唯一静态的方法,Proxy.revocable(target, handler), 可以用来创建一个可撤销的代理对象

该方法的返回值是一个对象,其结构为: {"proxy": proxy, "revoke": revoke}

  • proxy 表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉。
  • revoke 撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。

应用场景

  • 校验器

    使用Proxy实现一个逻辑分离的数据格式验证器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    const target = {
    id: 123,
    name: 'alice'
    }

    const validators = {
    name(val) {
    return typeof val === 'string'
    },
    id(val) {
    return typeof val === 'number'
    }
    }

    const createValidator = (target, validator) => {
    return new Proxy(target, {
    _validator: validator,
    set(target, propkey, value, proxy) {
    let validator = this._validator[propKey](value)
    if (validator) {
    return Reflect.set(target, propkey, value, proxy)
    } else {
    throw Error(`Cannot set ${propkey} to ${value}. Invalid type.`)
    }
    }
    })
    }
    • 私有属性

      使用Proxy轻松实现私有属性拦截

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      let target = {
      _id: 123
      }

      const proxy = new Proxy(target, {
      get(target, propkey, proxy) {
      if (propkey[0] === '_') {
      throw Error(`${propkey} is restricted`)
      }
      return Reflect.get(target, propkey, proxy)
      },
      set(target, propkey, value, proxy) {
      if(propkey[0] === '_'){
      throw Error(`${propkey} is restricted`)
      }
      return Reflect.set(target, propkey, value, proxy)
      }
      })

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!