本文主要抽离Vue源码中数据双向绑定的核心代码,解析Vue是如何实现数据的双向绑定
核心思想是ES5的Object.defineProperty()和发布-订阅模式
整体结构
- 改造Vue实例中的data,通过Object.defineProperty()将其所有属性设置为访问器属性
- 对每个属性添加Observer,并在observer中添加订阅者对象序列Dep
- 添加订阅者对象Watcher,每次初始化的时候添加到对应data属性中的Dep之中
所有,我们从代码的角度将整体分为三个部分:监听数据变化、管理订阅者、订阅者
监听数据变化
使用ES5中的Object.defineProperty将data中的属性修改为访问者属性
1 | // Dep用于订阅者的存储和收集,将在下面实现 |
管理订阅者
对订阅者进行收集,存储和通知
1 | export default class Dep{ |
订阅者
每个watcher对象都是对data中每个属性的订阅,是多对一的关系,每个watcher只能对应一个data属性,而一个data属性可以对应多个watcher
1 | import Dep from 'Dep' |
实例
下边我们创建一个简易的Vue来实际运行下对数据的监听
1 | import Observer, {observe} from 'Observer' |
1 | import Vue from './Vue'; |
根据实例的输出结果,我们很奇怪的发现,只有对简单的数据监听才能实现数据双向绑定。
demo.$watch('a.ab', () => console.log('a.ab is changed'))注册订阅者并没有调用getterdemo.a.ab = 'AB'有监听到数据的变化,并没有调用对应的callbackdemo.b.push({'bbbb': 'BBBB'})对数值进行操作,并没有调用对应的callback
这是为什么呢?因为我们对数据的监听的实现,目前仅限于简单对应,对于某个属性内部有更多复杂属性时,就无能为力了。
为了实现进一步对数据和复杂对象的监听,请戳Vue源码解析—数组的双向绑定和Vue源码解析—复杂队形的双向绑定