大家都知道Vue中的属性data是响应式的,那么这是怎么实现的呢?
Vue.js的响应式原理依赖于Object.defineProperty,Vue通过设定对象属性的 setter/getter 方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。
通过一个简单的例子来说明一下我的理解
let myData = {
n:0
}
let data5 = proxy2({data:myData})
function proxy2(value){
let {data} = value
let value1 = data.n
// delete data.n
Object.defineProperty(data,'n',{
get(){
return value1
},
set(newValue){
if(newValue<0)return
value1 = newValue
}
})
const obj = {} // 代理
Object.defineProperty(obj,'y',{
get(){
return data.n
},
set(newValue){
data.n = newValue
}
})
return obj
}
- 首先将myData赋值给data
- 将data中的n赋值给value1
- 删除data中的属性n,其实也可以不删除,后面也会通过Object.defineProperty将n属性删除并生成一个虚拟属性n
- 通过Object.defineProperty对myData进行监听和代理,obj下的y负责代理,data下已经被改写的n配合value1负责监听。
- 具体步骤是这样的 通过obj下的y进行代理,obj.y触发它的get函数get(),data.n 又触发了data下的get函数,返回value1的值
- obj.y=1触发它的set函数set(1),data.n = 1又触发data下的set(1),进行判断是否小于0,是的话直接返回,不是的话可以将1赋值给value1
console.log(myData);
console.log(Object.getOwnPropertyNames(myData));
console.log(data5);
console.log(Object.getOwnPropertyNames(data5));
console.log(myData.n = -1);
console.log(myData.n);
console.log(myData.n = 8);
console.log(myData.n);
data5.y = 4
console.log(myData.n);
console.log(data5.y);
通过log方法验证自己的想法加深理解
Vue对data做了什么呢
//创建一个Vue实例
const vm = new Vue({
data : mydata
})
Vue会让vm成为mydata的代理对象,并监听mydata上属性的变化.这样的话
- 你可以使用 this 来访问到 vm。 this.n === myData.n。
- 之所以要监控,就是防止 vue 无法得知 myData 的属性变化。
- vue 得知属性变化才可以使用 render(data) 来更新 UI 和渲染页面。
data Bug
Vue 虽然对 data 中的属性(或对象中的属性)进行监听和代理,但是它却没有办法进行事先的监听和代理。
使用Vue提供的api,在object上新增一个属性,自动给它代理和监听
Vue.set(object, key, value)
或
this.$set(object, key, value)
数组的话也是如此,Vue提供数组变异方法,一共有7个API。 这些方法 (API) 会自动处理对数组该项的监听和代理,并触发视图更新。