理解Vue数据响应式

我心飞翔 分类:javascript

一、数据响应式

Vue.js 一个核心思想是数据驱动。所谓数据驱动,是指视图是由数据驱动生成的,我们对视图的修改,不会直接操作 DOM,而是通过修改数据。

下图是Vue的官方文档中的图解,黄色部分是 Vue 的渲染方法,视图初始化和视图更新时都会调用render 方法进行重新渲染。渲染时不可避免地会 touch 到每个需要展示到视图上的数据(紫色部分),触发这些数据的 get 方法从而收集到本次渲染的所有依赖。而当我们在修改这些收集到依赖的数据时,会触发数据中的 set 属性方法,该方法会修改数据的值并 notify 到依赖到它的观察者,从而触发视图的重新渲染。

捕获.JPG

而我们定义在data中的数据并没有set,get的计算属性,get、set方法是如何产生的呢?这便是Vue的数据响应式的核心工作,重写数据的 get 和 set 属性方法。

二、让数据变成响应式

1、getter、setter

let obj = {
firstName: "dl",
lastName: "xx",
get name() {
return this.firstName + this.lastName;
},
set name(value){
this.firstName = value[0]
this.lastName = value.slice(1)
},
age: 18
};

obj.name = 'dlcc'
console.log( obj.name);
 
const Vue = window.Vue

const myData = {
  n:0
}

new Vue({
  data: myData,
  template: `
    <div>{{n}}</div>
  `
}).$mount('#app')

setTimeout(() => {
  myData.n += 10
}, 0)

console.log(myData)
 

在控制台进行打印就会发现 name属性下的getter、setter方法就和实例化vue中的data 里的值n打印出来变为了n:(...),也有getter、setter方法。

说明vue重写数据n,将其转换为getter/setter的对象属性。

2、Object.defineProperty( )方法

Vue是通过 JS 标准内置对象方法 Object.defineProperty 来设定将data中普通的属性n转化为getter、setter方法的属性n的。

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。

语法
Object.defineProperty(obj, prop, descriptor)

参数

obj:要在其上定义属性的对象。

prop:要定义或修改的属性的名称。

descriptor:将被定义或修改的属性描述符。

返回值
被传递给函数的对象。

3、proxy() 代理

let myData = {
    n: 0
}
let data = proxy({
    data: myData
}) // 括号里是匿名对象,无法访问
function proxy({ data } /* 解构赋值 */ ) {
    //for循环省略
    let value = data.n
    Object.defineProperty(data, 'n', {
        get() {
            return value
        },
        set(newValue) {
            value = newValue
        }
    })
    
    const obj = {}
    Object.defineProperty(obj, 'n', {
        get() {
            return data.n
        },
        set(value) {
            data.n = value
        }
    })
    return obj // obj 就是代理
}
 

上面的方法对每个传入的数据新增 getter/setter,此后原始的数据就会被 getter/setter 所替代,相当于复制了原始数据,这样不管是操作let data = proxy(data); 中的 data,还是操作 myData,都会被我们的 getter/setter 所拦截。

结论:Vue会遍历传入的data对象所有属性,并使用Object.defineProperty把这些属性全部转为getter/setter,这样就生成一个新的对象全权负责数据——就是实例化的Vue对象vm。这样vm会成为data 的代理,对 data 的所有属性进行监控,当数值发生改变的时候,vue就调用render函数重新渲染视图。

三、Vue 的数据响应式

当你创建一个实例时

const vm = new Vue({data:{n: 0}})
 
  • vue 会让 vm 成为 myData 的代理。
  • vue 会对 myData 的所有属性进行监控。

1、在 data 中添加属性

对于一般的对象来说,可以在 data 中预先把所有可能用到的属性全部写出来,这样并不需要新增属性,只需要改它。
也可以通过其他方法来添加属性。
在了解以上原理后,我们来了解 Vue 提供的一个 API:

Vue.set(object, key, value)
或
this.$set(object, key, value)
 

2、对数组的方法

vue对数组进行了改变,给数组加了一层原型,在其中Vue修改了7个方法覆盖了之前数组原型的7个方法。调用这些Vue新定义的方法时,在这些新方法里Vue会加上对新添的元素的监听(相当于进行了set操作),把新数据也进行代理,这样vue就能重新监测到数组的变化了更新UI操作
具体的七个变更方法:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

回复

我来回复
  • 暂无回复内容