proxy 和 Object.defineProperty

221 阅读1分钟

1 - Proxy

 const o = { a: 1 }
 const proxy = new Proxy(o, {
     get(target, key, receiver) {
         console.info('get')
         // return target[key]
         return Reflect.get(target, key, receiver)
     },
     set(target, key, value, receiver) {
         console.info('set')
         target[key] = value
         // return true // set 最后需要 return true 表示赋值成功,否则会报错
        return Reflect.set(target, key, value, receiver)
     }
 })
 
 proxy.b = 2  // proxy 可以监听到新增的属性

2 - Object.defineProperty

const o = { a: 1 }
const defineReactive = (target, key, midValue, configurable = true, enumerable = true) => {
    Object.defineProperty(o, 'a', {
        configurable,
        enumerable,
        get() {
            console.info('get:' + midValue)
            return midValue
        },
        set(value) {
            console.info('set:' + value)
            midValue = value
        }
    })
}
defineReactive(o, 'a', o['a'])

3 - proxy 和 defineProperty 的区别

1、proxy 代理的 set 方法中需要 return true,否则会报错

2、defineProperty 会拦截原对象,只需访问或修改 原对象 即可触发get、set方法。

​ proxy会对原对象进行代理,需要访问或改变 代理后的对象 才能触发get、set等方法

3、defineProperty 的 get 方法没有参数,需要一个中间值(midValue)去记录 set 方法触发时改变后的新值

​ proxy 由于监听的是对象, get 方法有参数 target、key(set也有),可以直接获取到访问的值,并return出去

4、proxy 除了 get 和 set ,还有其他拦截方法,比如监听数组,监听对象属性的新增,删除等,共13种。

5、当对象上新增属性时,proxy 可以监听到对象新增的属性。

​ defineProperty 无法监听到新增的属性,需要手动监听(Vue2.x 中的 $set 方法,在 3.0 中废除掉了 )

4 - Vue3.0 使用 Proxy 的优势

① 在 Vue2.x 中,对象上新增的属性不会触发视图更新,因为Object.defineProperty 无法监听到新增的属性,需要使用 Vue 提供的 $set 方法手动拦截监听(会通过Object.defineProperty将该属性进行拦截监听)

<div>{{ obj }}</div>

export default {
  data() {
    return {
      obj: {
        name: 'xhl'
      }
    }
  },
  mounted() {
    // this.obj.age = 24    // 不会更新视图
    this.$set(this.obj, 'age', 24) // √
  },
}

在 Vue3.0 中废除了 $set 方法,因为 Proxy 可以监听到对象上新增的属性