当前位置 主页 > 网站技术 > 代码类 >

    为什么Vue3.0使用Proxy实现数据监听(defineProperty表示不背这个

    栏目:代码类 时间:2019-11-08 15:02

    导 读

    vue3.0中,响应式数据部分弃用了 Object.defineProperty ,使用 Proxy 来代替它。本文将主要通过以下方面来分析为什么vue选择弃用 Object.defineProperty

    Object.defineProperty 真的无法监测数组下标的变化吗? 分析vue2.x中对数组 Observe 部分源码 对比 Object.definePropertyProxy

    一、无法监控到数组下标的变化?

    在一些技术博客上看到过这样一种说法,认为 Object.defineProperty 有一个缺陷是无法监听数组变化:

    无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。所以vue才设置了7个变异数组( pushpopshiftunshiftsplicesortreverse )的 hack 方法来解决问题。

    Object.defineProperty 的第一个缺陷,无法监听数组变化。 然而Vue的文档提到了Vue是可以检测到数组变化的,但是只有以下八种方法, vm.items[indexOfItem] = newValue 这种是无法检测的。

    这种说法是有问题的,事实上, Object.defineProperty 本身是可以监控到数组下标的变化的,只是在 Vue 的实现中,从性能/体验的性价比考虑,放弃了这个特性。

    下面我们通过一个例子来为 Object.defineProperty 正名:

    function defineReactive(data, key, value) {
     Object.defineProperty(data, key, {
     enumerable: true,
     configurable: true,
     get: function defineGet() {
     console.log(`get key: ${key} value: ${value}`)
     return value
     },
     set: function defineSet(newVal) {
     console.log(`set key: ${key} value: ${newVal}`)
     value = newVal
     }
     })
    }
    
    function observe(data) {
     Object.keys(data).forEach(function(key) {
     defineReactive(data, key, data[key])
     })
    }
    
    let arr = [1, 2, 3]
    observe(arr)

    上面代码对数组arr的每个属性通过 Object.defineProperty 进行劫持,下面我们对数组arr进行操作,看看哪些行为会触发数组的 gettersetter 方法。

    1. 通过下标获取某个元素和修改某个元素的值

    可以看到,通过下标获取某个元素会触发 getter 方法, 设置某个值会触发 setter

    方法。

    接下来,我们再试一下数组的一些操作方法,看看是否会触发。

    2. 数组的 push 方法

    push 并未触发 settergetter 方法,数组的下标可以看做是对象中的 key ,这里 push 之后相当于增加了下索引为3的元素,但是并未对新的下标进行 observe ,所以不会触发。

    3. 数组的 unshift 方法

    我擦,发生了什么?

    unshift 操作会导致原来索引为0,1,2,3的值发生变化,这就需要将原来索引为0,1,2,3的值取出来,然后重新赋值,所以取值的过程触发了 getter ,赋值时触发了 setter

    下面我们尝试通过索引获取一下对应的元素: