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

ES6 Proxy 与 Object.defineProperty 的优劣对比?

程序员文章站 2022-07-16 18:05:19
...

Proxy 的优势如下:

  • Proxy 可以直接监听数组的变化
  • Proxy 可以直接监听对象而非属性
  • Proxy 有 13 种拦截方法,比 Object.defineProperty 要更加丰富的多

Object.defineProperty 的优势如下:

  • 兼容性好

Object.defineProperty (obj, prop, descriptor) 的问题主要有三个:

  • 无法监听数组的变化
  • 必须遍历对象的每个属性
  • 必须深层遍历嵌套的对象

(1)无法监听数组的变化

Vue 把会修改原来数组的方法定义为变异方法。

变异方法例如 push、pop、shift、unshift、splice、sort、reverse等,是无法触发 set 的。

非变异方法,例如 filter,concat,slice 等,它们都不会修改原始数组,而会返回一个新的数组。

Vue 的做法是把这些变异方法重写来实现监听数组变化。

const aryMethods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse',
]
const arrayAugmentations = []

aryMethods.forEach((method) => {
  // 这里是原生 Array 的原型方法
  let original = Array.prototype[method]

  // 将 push, pop 等封装好的方法定义在对象 arrayAugmentations 的属性上
  // 注意:是实例属性而非原型属性
  arrayAugmentations[method] = function () {
    console.log('我被改变啦!')

    // 调用对应的原生方法并返回结果
    return original.apply(this, arguments)
  }
})

let list = ['a', 'b', 'c']
// 将我们要监听的数组的原型指针指向上面定义的空数组对象
// 这样就能在调用 push, pop 这些方法时走进我们刚定义的方法,多了一句 console.log
list.__proto__ = arrayAugmentations
list.push('d') // 我被改变啦!

// 这个 list2 是个普通的数组,所以调用 push 不会走到我们的方法里面。
let list2 = ['a', 'b', 'c']
list2.push('d') // 不输出内容

 (2)必须遍历对象的每个属性

使用 Object.defineProperty 多数情况下要配合 Object.keys 和遍历,于是就多了一层嵌套。

并且由于遍历的原因,假如对象上的某个属性并不需要“劫持”,但此时依然会对其添加“劫持”。

Object.keys(obj).forEach((key) => {
  Object.defineProperty(obj, key, {
    // ...
  })
})

 (3)必须深层遍历嵌套的对象

当一个对象为深层嵌套的时候,必须进行逐层遍历,直到把每个对象的每个属性都调用 Object.defineProperty() 为止。


以上。