4

在Vue2和3 中 defineProperty 和 Proxy 都是用来实现响应式数据绑定的。实现的功能类似,但是两个API却有着本质的区别。

  1. 监听数据的角度

    1. defineproperty只能监听某个属性而不能监听整个对象。
    2. proxy不用设置具体属性,直接监听整个对象。
    3. defineproperty监听需要知道是哪个对象的哪个属性,而proxy只需要知道哪个对象就可以了。也就是会省去for in循环提高了效率。
  2. 监听对原对象的影响

    1. 因为defineproperty是通过在原对象身上新增或修改属性增加描述符的方式实现的监听效果,一定会修改原数据。
    2. proxy只是原对象的代理,proxy会返回一个代理对象不会在原对象上进行改动,对原数据无污染。
  3. 实现对数组的监听

    1. 因为数组 length 的特殊性 (length 的描述符configurable 和 enumerable 为 false,并且妄图修改 configurable 为 True 的话 js 会直接报错:VM305:1 Uncaught TypeError: Cannot redefine property: length)
    2. defineproperty无法监听数组长度变化, Vue只能通过重写数组方法的方式变现达成监听的效果,光重写数组方法还是不能解决修改数组下标时监听的问题,只能再使用自定义的$set的方式
    3. proxy因为自身特性,是创建新的代理对象而不是在原数据身上监听属性,对代理对象进行操作时,所有的操作都会被捕捉,包括数组的方法和length操作,再不需要重写数组方法和自定义set函数了。(代码示例在下方)

    4. 监听的范围

    1. defineproperty只能监听到valueget set 变化。
    2. proxy可以监听除 [[getOwnPropertyNames]] 以外所有JS的对象操作。(链接看下方)监听的范围更大更全面。

点击查看proxy支持监听的对象操作方法(除getOwnPropertyNames)

Proxy监听数组变化示例:

let array = ['1', '2']
let arrayProxy = new Proxy(array, {
    get(target, key) {
        console.log('(key:', key + ") 发生了get操作")
        return target[key]
    },
    set(target, key, value) {
        console.log('(key:', key + ") 发生了set操作, value= " + value)
        return target[key] = value
    }
})
arrayProxy.push('我是push函数push到数组中的值')

// (key: push) 发生了get操作
// (key: length) 发生了get操作
// (key: 2) 发生了set操作, value= 我是push函数push到数组中的值
// (key: length) 发生了set操作, value= 3

// 从log可以看出push length等操作都被捕捉了

海洋饼干
1.5k 声望191 粉丝