对Vue数据响应式的理解

710 阅读2分钟


前言

Vue.js的核心包括一套“响应式系统”。

“响应式”,我打你一拳,你会喊疼,那你就是响应式。若一个物体能对外界的刺激作出反应他就是响应式的。

当数据改变后,Vue会通知到使用该数据的代码。视图渲染中使用了数据,数据改变后,视图也会自动更新。


基本概念

Vue的相应式,核心机制是观察者模式。

数据是被观察的一方,当数据发生改变,通知所有的观察者,这样的观察者可以作出响应,比如,重新渲染然后更新视图。

我们把依赖数据的观察者称为 watcher,可以表示为:

data -> watcher

Vue通过在 data 和 watcher 间创建一个dep对象,来记录这种依赖关系:

data - dep -> watcher

dep的结构很简单,除了唯一的标识属性id,另一个就是记录所有观察者的subs:

id - number
subs - [Watcher]

正文:

Vue.js的响应式原理依赖于Object.defineProperty,Vue通过设定对象属性setter/getter方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

一、Vue对Data做了什么?

示例代码:

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)

在myData 传给 Vue 的时候 ,数值就会发生改变。

myData变了,一开始是{n:0},传给new Data之后立马变成{n:(...)}。

vue监听了这个数值,vue 会让 vm 成为 myData 的代理,vue 会对 myData 的所有属性进行监控,当数值发生改变的时候,vue就重新渲染。

而原理是把一个普通的 JavaScript 对象传入 Vue 实例作为data选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter。Object.defineProperty是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。

二、数据响应式

  • 响应式即对外界的变化做出的反应的一种形式。
  • const vm = new Vue({data:{n: 0}})。
  • 当修改 vm.n 或 data.n 时,render(data...) 中的 n 就会做出响应的响应。
  • 这个联动的过程就是 vue 的 数据响应式。
  • vue 目前通过 Object.defineProperty 来实现数据响应式。