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

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() 为止。


以上。

你可能感兴趣的:(es6,javascript,前端)