欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Proxy 和 Object.defineProperty 区别以及常见使用场景

程序员文章站 2022-07-12 22:57:35
...

在日常开发中,我们需要经常对对象进行对象层面和属性层面的很多操作,既然是操作,那么我们就希望能够具备对这些操作进行切面处理的能力,也即实现代理操作,那么应该怎么做呢?

Object.defineProperty 简单介绍

Object.defineProperty 是 ES5 中一个很重要的数据劫持的方法,它提供了存取器属性get、set,这让我们具备了代理一个对象的属性读写操作以进行切面处理的能力。但是这时候对于其它对对象操作行为的代理方案仍然没有官方的实现方案。

Proxy 简单介绍

Proxy是ES6中一个新内置对象(函数类型对象),它的实例对象用于定义对象基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等),Proxy出现,我们才具备了对这些各种类型的对象操作进行代理以进行切面处理的能力。

两者对比

既然Object.defineProperty和Reflect都可以代理对象操作,那么我们对比一下两者的代理原理和优缺点以备往后甄选方案:

  • 代理原理:Object.defineProperty的原理是通过将数据属性转变为存取器属性的方式实现的属性读写代理。而Proxy则是因为这个内置的Proxy对象内部有一套监听机制,在传入handler对象作为参数构造代理对象后,一旦代理对象的某个操作触发,就会进入handler中对应注册的处理函数,此时我们就可以有选择的使用Reflect将操作转发被代理对象上
  • 代理局限性:Object.defineProperty始终还是局限于属性层面的读写代理,对于对象层面以及属性的其它操作代理它都无法实现。鉴于此,由于数组对象push、pop等方法的存在,它对于数组元素的读写代理实现的并不完全。而使用Proxy则可以很方便的监视数组操作
  • 自我代理:Object.defineProperty方式可以代理到自身(代理之后使用对象本身即可),也可以代理到别的对象身上(代理之后需要使用代理对象)。Proxy方式只能代理到Proxy实例对象上。这一点在其它说法中是Proxy对象不需要侵入对象就可以实现代理,实际上Object.defineProperty方式也可以不侵入。

常见使用场景

Object.defineProperty 可以说目前已经过时,未来都将会使用 Proxy 来替代 Object.defineProperty,目前的Vue3.0版本就已经使用了Proxy来实现数据的双向绑定,在这里就只叙述在日常开发中我们可能会见到或者用到Proxy代理的场景:

(1)实现属性读写AOP(切面处理

const person = {
  name: 'abc',
  age: 20
}

const personProxy = new Proxy(person, {
  get (target, property) {
    return property in target ? target[property] : 'default'
  },

  set (target, property, value) {
    if (property === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError(`${value} is not an int`)
      }
    }
    target[property] = value
  }
})

personProxy.age = 100
personProxy.gender = true
console.log(personProxy.name)
console.log(personProxy.xxx)

(2)实现数组操作的监视

const list = []

const listProxy = new Proxy(list, {
  set (target, property, value) {
    console.log('set', property, value)
    target[property] = value
    return true // 表示设置成功
  }
})

listProxy.push(100)
listProxy.push(100)