Object.defineProperty和proxy的区别

3,519 阅读2分钟

两者经常被用作数据劫持。

数据劫持:在访问或者修改对象某个属性时,通过一个代码的拦截行为,进行额外的操作或修改返回结果。数据劫持应用在数据双向绑定。

Vue2.x利用Object.defineProperty(),并将内部解耦为Observer、Dep,并使用watcher相连

Vue3.x版本后使用proxy进行

另外一种应用是在immer.js,保证数据的immutable属性,使用proxy来阻断常规的修改操作

应用:

1、Object.defineProperty()



Object.defineProperty的问题有三个:

  1. 不能监听数组的变化(数组的这些方法不能触发set:push、pop、shift、unshift、splice、sort、reverse)。Vue对其变异方法进行重写。
  2. 必须遍历对象的每个属性(Object.defineProperty多数要配合Object.keys使用)

    Object.keys(obj).forEach(key => {
    Object.defineProperty(obj, key, {
      ...
    })})

  3. 必须深层遍历嵌套的对象(当一个对象为深层嵌套时,必须逐层遍历,直到把每个对象都调用到Object.defineProperty为止 )Vue源码中这样的逻辑-walk方法

2、Proxy


  • 支持数组:不需要对数组方法进行重载,省去了众多hack

    let arr = [1,2,3]
    let proxy = new Proxy(arr, {
        get(target, key, receiver) {
            console.log('get', key)
            return Reflect.get(target, key, receiver)
        },
        set(target, key, value, receiver){
             console.log('set', key, value)
             return Reflect.get(target, key, value, receiver)
        }})
    proxy.push(4)
    //打印内容
    VM1087:4 get push
    VM1087:4 get length
    VM1087:8 set 3 4
    VM1087:8 set length 4
    4

  • 针对对象:针对整个对象,而不是对象的某个属性 (省略了Object.keys()的遍历。Reflect是一个内置对象,提供拦截js的方法。这些方法与处理器对象方法相同。Reflect不是函数对象,因此它是不可构造的。Reflect.get() Reflect.set())
  • 嵌套支持:get里面递归调用proxy并返回

    let obj = { a:[1, 2, 3], b:1 }
    let handler = {
        get(target, key, receiver) {
            console.log('get', key)
            if(typeof target[key] === 'object' && target[key] !== null)
               return new Proxy(target[key], handler)
            return Reflect.get(target, key, receiver)
        },
       set(target, key, value, receiver) {
           console.log('set', value)
           return Reflect.set(target, key, value, receiver)
       }}
    let proxy = new Proxy(obj, handler)
    proxy.b = 8
    proxy.a.push(4)
    

其它方面  

优势:Proxy 的第二个参数可以有 13 种拦截方法,比 Object.defineProperty() 要更加丰富,Proxy 作为新标准受到浏览器厂商的重点关注和性能优化,相比之下 Object.defineProperty() 是一个已有的老方法。 

劣势:Proxy 的兼容性不如 Object.defineProperty() (caniuse 的数据表明,QQ 浏览器和百度浏览器并不支持 Proxy,这对国内移动开发来说估计无法接受,但两者都支持 Object.defineProperty()),不能使用 polyfill 来处理兼容性


转载:blog.csdn.net/qq_42833001…