目录
数据劫持(代理)
Vue监测数据变化原理及步骤:
一、监测对象中的数据
data对象加工成_data对象,并存入Vue实例
添加reactive getter和reactive setter:
数据变化监测效果
注意:
二、监测数组中的数据
在Vue修改数组中的某个元素需要用到以下方法:
数据劫持(代理)
数据劫持是实现数据代理的一种技术。Vue2.x中使用的是Object.defineProperty() ,因此我们有必要学习下这个函数的作用。
在MDN中有如下描述:
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
传入三个参数,被定义的对象obj、obj中的属性名、描述符。其中描述符分为数据描述法和存取描述符。这里主要使用存取描述符就可以实现数据代理。
Object.defineProperty 缺点
- 深度监听时,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性(所以开发中需要使用 Vue.set 和 Vue.delete 这两个 API 来增删 data 的属性)
- 无法原生监听数组,需要特殊处理
let a = {
name:"badspider"
}
let b = {}
object.defineProperty(b,'name',{
get(){
console.log('我被调用了')
return a.name
}
set(value){
console.log('我被修改了')
return a.name = value
}
})
Vue监测数据变化原理及步骤:
一、监测对象中的数据
data对象加工成_data对象,并存入Vue实例
Vue首先对options中的data对象进行加工,生成_data对象,并存入全局Vue实例中
生成_data对象:递归为每一个非对象类型的数据添加响应式的get、set方法(reactive getter、reactive setter)(数据劫持)
添加reactive getter和reactive setter:
let data = {
key1:value1,
key2:value2,
}
// 创建一个观察者实例对象,用于监测data的数据变化
const obs = new Observer(data)
function Observer(obj){
// 汇总obj中所有属性,形成一个数组keys
const keys = Object.keys(obj)
//Object.keys(obj) 返回值:一个表示给定对象的所有可枚举属性的字符串数组
// 遍历keys数组(此处为简化示例,未体现属性是一个对象或一个数组进行递归的情况)
keys.forEach((key)=>{
Object.defineProperty(this,key,{
get(){
return obj[key]
},
set(value){
obj[key] = value
}
})
})
}
数据变化监测效果
每个具有reactive setter的数据发生变化时,都会调用这个reactive setter,而这个reactive setter被调用时,会触发重新解析模板、生成新的虚拟DOM,、新旧虚拟DOM对比,更新内容映射到真实DOM、重新渲染这一套流程。
注意:
? (1)在对象后追加的属性,Vue默认不做响应式处理
? (2)如需给后添加的属性做响应式,需要使用以下API:
? Vue.set(target,propertyName/index,value)
? vm.$set(target,propertyName/index,value)
二、监测数组中的数据
如何监听数组变化
由于性能因素,Vue 不是通过 Object.defineProperty() 来监听数组的。
对于数组,是通过重写数组方法来实现,共修改了两处:
- 对原生数组原型做一个备份(防止后续的操作污染原生数组原型),基于这个备份创建一个新的数组,并扩展(在执行原方法前触发一次视图更新)它的方法。
- observer 方法中,增加对数组的处理。
在Vue修改数组中的某个元素需要用到以下方法:
? 1.使用这些API:
push(),pop(),shift(),unshift(),splice(),sort(),erverse()
? 2.Vue.set()或vm.$set
由于Vue本身有规定,不能把一个响应式的属性直接添加到Vue实例身上,而data对象中的所有属性最终都会通过数据代理添加到Vue实例身上,因此Vue.set()方法和this.$set()方法的targetObject这个参数不能是Vue实例本身,也不能是data对象,只能是data对象中的二级属性对象。
|