浅析Vue中的data属性

419 阅读2分钟

大家都知道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
}
  1. 首先将myData赋值给data
  2. 将data中的n赋值给value1
  3. 删除data中的属性n,其实也可以不删除,后面也会通过Object.defineProperty将n属性删除并生成一个虚拟属性n
  4. 通过Object.defineProperty对myData进行监听和代理,obj下的y负责代理,data下已经被改写的n配合value1负责监听。
  5. 具体步骤是这样的 通过obj下的y进行代理,obj.y触发它的get函数get(),data.n 又触发了data下的get函数,返回value1的值
  6. 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方法验证自己的想法加深理解

image.png

Vue对data做了什么呢

//创建一个Vue实例
const vm = new Vue({
   data : mydata
})

Vue会让vm成为mydata的代理对象,并监听mydata上属性的变化.这样的话

  1. 你可以使用 this 来访问到 vm。 this.n === myData.n。
  2. 之所以要监控,就是防止 vue 无法得知 myData 的属性变化。
  3. 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) 会自动处理对数组该项的监听和代理,并触发视图更新。