我对Vue数据响应式的理解

153 阅读1分钟

Vue 最独特的特性之一,使其响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。

什么是响应式?

我给你一拳,你会喊疼,那你就是响应式的。

若一个物体能对外界的刺激做出响应,那么它就是响应式的。

思考一个问题,Vue 到底对 data 做了什么呢?

看一个示例代码

index.html

<body>
  <div id="app"></div>
  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</body>

main.js

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)

控制台

 {__ob__: we}
     n: (...)
     __ob__: we {value: {...}, dep: ce, vmCount: 1}
     get n: f ()
     set n: f (t)
     __proto__: Object

可以看到,在将 data 传给 Vue后,Vue 会将它篡改。

Vue 为对象添加了 getter/setter 。

getter/setter 用于对属性的读写进行监控。

那么 Vue 是如何为对象添加属性的呢?

使用object.difineProperty() 方法。

Object.defineProperty( ) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。

语法

Object.defineProperty(obj, prop, descriptor)

  • obj -- 要在其上定义属性的对象。
  • prop -- 要定义或修改的属性的名称。
  • descriptor--将被定义或修改的属性描述符。

返回值

被传递给函数的对象。

vm=new Vue({data:myData})

  1. 会让 vm 成为 myData 的代理(proxy)
  2. 会对 myData 的所有属性进行监控,当 myData 改变时,vm可以马上知道,并render(data),更新视图界面

Vue数据响应式总结

响应式即对外界的变化做出的反应的一种形式。

const vm = new Vue({data:{n: 0}})

当修改 vm.n 或 data.n 时,render(data...) 中的 n 就会做出响应的响应。

这个联动的过程就是 vue 的 数据响应式。

vue 目前通过 Object.defineProperty 来实现数据响应式。

Vue 的data有bug?

看一段代码:

import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

new Vue({
  data: {
    obj: {
      a: 0 // obj.a 会被 Vue 监听 & 代理
    }
  },
  template: `
    <div>
      {{obj.b}}
      <button @click="setB">set b</button>
    </div>
  `,
  methods: {
    setB() {
      this.obj.b = 1; //请问,页面中会显示 1 吗?
    }
  }
}).$mount("#app");

页面中并不会显示1

Vue 虽然对 data 中的属性(或对象中的属性)进行监听和代理,但是它却没有办法进行事先的监听和代理。

如果你在初始化 data 之后再添加属性,该如何实现?

一般对象

Vue.set(object, key, value)

this.$set(object, key, value)

作用

在 data 中添加新的属性。

自动创建为它创建代理和监听(如果没有创建过)。

数组

Vue 提供了七个数组变更方法。

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

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