Vue实现数据响应式

85 阅读2分钟

Vue实现数据响应式,主要就是两种方式:

  1. Object.defineProperty
  2. ES6新特性--代理Proxy

1、Object.defineProperty

通过该方法的getter、setter来进行对该对象现存的元素进行数据劫持,劫持的是对象的属性,但是这种方法是有局限性的。如果新增一个属性或者删除一个属性、根据数组的索引进行增删替换也不会触发该方法的setter。因此在Vue2中,数组的元素想要实现响应式,将数组方法进行了重写。(例如:splice、push、pop、shift、unshift、sort、reverse)

Object.defineProperty( object(需要监视的对象), key(需要监视的属性) , {
    get(){
       //访问该属性时返回该属性的值
       return object[key]
    },
    set(newValue){
       //一旦该属性发生改变,触发setter,将新增的值赋值给该属性
       object[key]  = newValue
    }
})

2、Proxy

ES6中提供了原生的Proxy构造函数,生成Proxy实例对象从而实现对整个目标对象进行拦截(代理),对这代理可以进行数据的监控,无论是对象属性的新增、删除还是对于数组根据索引改变该数组的值都能够进行实时的监控,从而可以通过该代理来改变目标对象的值。该构造函数的第二个值是handle对象,里面还有其他的方法,可以看 MDN文档

    //new一个代理的实例对象
    const proxy = new Proxy( object(需要进行代理的对象),{
        get( target , propName ){
            //只要访问该属性则触发getter,返回该属性的值
            return target[propName]
        },
        set( target , propName, newValue ){
            //只要该属性的值发生改变或者有新的属性添加都会触发setter,从而改变该对象的值
            target[propName] = newValue
        },
        deleteProperty( target, propName ){
            return delete target[propName]  //成功删除则返回true
        }
    })

Reflect

Reflect是ES6提供的一个对象,主要就是将对象Object上面的一些属性方法搬到Reflect上面,同时以函数的方式来展示结果,比如:Object.属性 === Reflect.get(Object,属性名) 这样的做法看似是多此一举,其实是为了能增强代码的健壮性。Reflect能够返回这个操作是否成功的返回值(返回false则是有错误),而不会卡住js的进程或者无法准确的debug,由此Vue3中的数据劫持不仅是运用了Proxy来进行数据的响应式,也运用了Reflect来返回对象的操作结果

 //new一个代理的实例对象
 const proxy = new Proxy( object(需要进行代理的对象),{
     get( target , propName ){
         //只要访问该属性则触发getter,返回该属性的值
         return Reflect.get(target,propName)
     },
     set( target , propName, newValue ){
         //只要该属性的值发生改变或者有新的属性添加都会触发setter,从而改变该对象的值
         Reflect.set(target,propName,newValue)
     },
     deleteProperty( target, propName ){
         return Reflect.delete(target,propName)  //成功删除则返回true
     }
 })