Vue实现数据响应式,主要就是两种方式:
- Object.defineProperty
- 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
}
})