目录

  1. 双向绑定方法
  2. Vue 双向数据绑定的原理

双向绑定方法

发布者-订阅者模式(backbone.js
脏值检查(angular.js
数据劫持(vue.js
发布者-订阅者模式: 一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value)
脏值检查: angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:
  DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
  XHR响应事件 ( $http )
  浏览器Location变更事件 ( $location )
  Timer事件( $timeout , $interval )
  执行 $digest()$apply()
数据劫持:
  vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调。
  Vue 响应系统,其核心有三点:observewatcherdep
    observe:遍历 data 中的属性,使用 Object.definePropertyget/set 方法对其进行数据劫持;
    dep:每个属性拥有自己的消息订阅器 dep,用于存放所有订阅了该属性的观察者对象;
    watcher:观察者(对象),通过 dep 实现对响应属性的监听,监听到结果后,主动触发自己的回调进行响应。
实现虚拟DOM包含以下三个步骤:
  用JS对象模拟DOM树
  比较两棵虚拟DOM树的差异, Diff算法
  映射成真实DOM

Vue 双向数据绑定的原理

Object​.define​Property()
属性描述符有两种主要形式:数据描述符存取描述符。数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。
Object.definePropertyES5新增的一个API,其作用是给对象的属性增加更多的控制
Object.defineProperty(obj, prop, descriptor)
参数 :
  obj: 需要定义属性的对象(目标对象)
  prop: 需被定义或修改的属性名(对象上的属性或者方法)
对于settergetter,我的理解是它们是一对勾子(hook)函数,当你对一个对象的某个属性赋值时,则会自动调用相应的setter函数;而当获取属性时,则调用getter函数。这也是实现双向数据绑定的关键。
  descriptor: 将被定义或修改的属性描述符。
描述:
  该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for...inObject.keys 方法), 这些属性的值可以被改变,也可以被删除。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改的。

整理思路
实现mvvm的双向绑定,就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者
observer用来实现对每个vue中的data中定义的属性循环用Object.defineProperty()实现数据劫持,以便利用其中的setter和getter,然后通知订阅者,订阅者会触发它的update方法,对视图进行更新。

1
2
3
4
5
6
7
我们介绍为什么要订阅者,在`vue`中`v-model`,`v-name`,`{{}}`等都可以
对数据进行显示,也就是说假如一个属性都通过这三个指令了,那么每当这个属性
改变的时候,相应的这个三个指令的html视图也必须改变,于是vue中就是每当有
这样的可能用到双向绑定的指令,就在一个Dep中增加一个订阅者,其订阅者只是
更新自己的指令对应的数据,也就是`v-model='name'`和`{{name}}`有两个对
应的订阅者,各自管理自己的地方。每当属性的set方法触发,就循环更新Dep中
的订阅者。

Object.defineProperty缺陷:
只能对属性进行数据劫持,对于JS对象劫持需要深度遍历;
对于数组不能监听到数据的变化,而是通过一些hack办法来实现,如push、pop、shift、unshift、splice、sort、reverse