vue2 的 Object.defineProperty 为什么不在 get 中递归?为什么 vue3 Proxy 中可以?

这是 vue2 采取数据监听的方式

function defineReactive(target, key, value) {
  //深度监听
  observer(value)

  Object.defineProperty(target, key, {
    get() {
      return value
    }
  })
}

这是 vue3 采取数据监听的方式,在 get 中才去监听

// reactive 中有 Proxy 操作
const handler = {
  get: function (obj, prop) {
    const res = Reflect.get(obj, prop)
    if (typeof res === 'object') {
      return reactive(res, handler)
    }
    return res
  }
}

const p = reactive(bigData, handler)

vue3 为了避免多次 get 导致的多次递归,在 reactive 中会判断是否已经被代理过,如果是会直接返回对象
vue2 为什么不这么做,反而是直接在代理属性时就选择数据监听,如果选择在 get 中,当数据被访问时再递归子对象/数组,这样不就不会有递归的性能问题了吗?

阅读 2.3k
3 个回答

可能是因为Object.defineProperty是针对对象单个属性进行监听的,所以要放在get中的话,需要一个一个遍历,性能影响是一方面,还有一方面是vue2中数组是不监听的,如果是一个数组对象,数组不监听,走不到get,还怎么监听里面的对象。

而proxy是针对对象本身去监听的,无论数组还是对象都可以监听,运行时监听可以减少其他无用数据监听带来的消耗

新手上路,请多包涵

所以,综合楼上所说,vue3判断对象是否被代理过是使用了WeakMap,这是一个ES6的语法,在当时的vue2是不可能使用的,当时来说对于WeakMap又没有什么好的替代品,所以vue2没有采用这样的判断机制。不知道我说的对否

推荐问题
宣传栏