Ajiu9

Proxy和Reflect

Oct 31, 2018

计算机中代理模式的定义:为其他对象提供一种代理以控制这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。

Proxy和Reflect

  • Proxy对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。

  • Reflect是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与处理器对象的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

Proxy的方法

let obj = {
time: '2018-10-31',
name: 'vender',
_r: 123

}
let monitor = new Proxy(obj, {
    //拦截对象读取属性值
    get(target, key) {
        return obj[key].replace(/-/g, ':')
    },
    //拦截对象设置属性值
    set(target, key, value) {
        if (key === 'name') {
        return target[key] = value
      } else {
        return target[key]
      }
    },
    // 拦截 key in object 操作
    has(target, key) {
    if (key === 'name') {
        return true
      } else {
        return false
    }
    // 拦截delete
    deleteProperty(target, key) {
        if (key === '_r') {
        delete target[key]
        return true
      } else {
        return target[key]
      }
    },
    // 拦截 Object.getOwnPropertyNames(),Object.getOwnProptySymbols(), Object.keys(), Reflect.ownKeys()
    ownKeys(target) {
        return Object.keys(target).filter(item => item !== 'time')
    }

})

上面定义了一个对象obj, 同时使用了Proxy代理分别拦截了get,set,has,deleteProperty,ownKeys五种比较常用的方法。

console.log('get', monitor.time) // get 2018:10:31

代理get方法拦截对象读取属性值。

monitor.time = '2019'
monitor.name = 'apple'
console.log('set', monitor.name, monitor) // set apple Proxy {time: "2018-10-31", name: "apple", _r: 123}

代理set方法拦截对象设置属性值。

console.log('has', 'name' in monitor, 'time' in monitor) // has true false

代理has方法拦截 key in object 操作。

delete monitor.name
console.log('delete', monitor) // delete Proxy {time: "2018-10-31", name: "apple", _r: 123}
delete monitor._r
console.log('delete', monitor) // delete Proxy {time: "2018-10-31", name: "apple"}

代理deleteProperty方法拦截delete。

console.log('ownKeys', Object.keys(monitor)) // ownKeys ["name"]

代理ownKeys方法拦截Object.getOwnPropertyNames(),Object.getOwnProptoSymbols(),Object.keys(),Reflect.ownKeys()

Reflect的方法

如前面所说,Reflect的方法与处理器对象的方法相同。Reflect不是一个函数对象,因此它是不可构造的。 一下简单举例:

const obj = {
  time: '2018-10-31',
  name: 'vender',
  _r: 123
}
console.log('Reflect get:', Reflect.get(obj, 'time')) // Reflect get: 2018-10-31Reflect.set(obj, 'name', 'banana')
console.log('Reflect set:', obj) // Reflect set: {time: "2018-10-31", name: "banana", _r: 123}
console.log('Reflect has:', Reflect.has(obj, 'time')) // Reflect has: trueReflect.deleteProperty(obj, '_r')
console.log('Reflect delete:', obj) // Reflect delete: {time: "2018-10-31", name: "banana"}
console.log('Reflect ownKeys:', Reflect.ownKeys(obj)) // Reflect ownKeys: ["time", "name"]

简单应用

在开发中通常会对数据进行校验,提交数据的时候会判断数据是否符合,利用ProxyReflect来实现一个简单的验证,实现数据和业务解耦,功能:1.对用户填写的原始数据进行验证。2.数据和业务解耦

思路:

  • 1.通过定义一个函数,这个函数的功能就是接收俩个参数(target原始对象和validator验证规则)返回一个代理对象,拦截原始对象的设置属性值,也就是set方法。
  • 2.定义一个类Person,在constructor中重写thisreturn validator(this, personValidator)这里返回的是代理对象)从而达到对这个对象实例的代理。
  • 3.定义第二步这个类Person所需要的验证规则定义personValidator,在这个对象里,实现对数据的具体验证。
  • 4.使用时,实例化第二步定义的类Person
// 定义一个验证函数,这个函数返回一个代理对象。它的功能就是验证
function validator(target, validator) {
  return new Proxy(target, {
    _validator: validator, // 保存原始校验对象
    set(target, key, value, proxy) {
      // 拦截target设置属性
      if (target.hasOwnProperty(key)) { // target属性key存在就继续下一步,不存在抛出错误
        const va = this._validator[key]
        if (va(value)) { // 校验规则是否通过
          return Reflect.set(target, key, value, proxy) // 拦截target设置属性,验证通过
        }
        else {
          throw new Error(`${key}不能设置为${value}`)
        }
      }
      else {
        throw new Error(`${key} 不存在`)
      }
    }
  })
}

// 定义验证规则
const personValidator = {
  name(val) {
    return typeof val === 'string'
  },
  age(val) {
    return typeof val === 'number' && val > 18
  }
}
// 定义类

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
    return validator(this, personValidator)
  }
}

// 实例
const person = new Person('wu', 20)
person.name = 'zhuli'
console.info(person) // Proxy {name: "hell", age: 20}

person.age = 'year' // Uncaught Error: age不能设置为year

>
@2024-2025 湘ICP备2024048835号