双向绑定

双向绑定

  数据的双向绑定可以说是MVVM框架的核心思想,MVVM框架包括三个部分,Model、View和ViewModel,分别指数据、视图、ViewModel可以说是前二者的连接者,二者通过它实现数据的双向绑定。以Vue为例,先看下Vue官网数据绑定的示意图:

数据绑定

  这张图想表达的是,对象a下的属性b定义了getter、setter对属性进行劫持,当属性值改变时就会notify通知watch对象,而watch对象则会notify到view更新。反之,在视图改变数据时,也会触发订阅者watch,更新数据到data中。这样的model能实时响应view上的数据变化,view实时响应model的数据变化,这样的一个过程就叫数据的双向绑定。

  Vue是通过ES5中Object.defineProperty()这个方法来实现getter、setter对数据进行劫持,所以要运行Vue的运行环境需支持ES5。

Object.defineProperty()

  这是一个ES5的方法,可以在一个对象上定义一个新属性或用来修改一个已经存在的属性,并返回该对象。目前对象的属性描述符有两种主要形式:此数据描述符和存取描述符。

  数据描述符是一个拥有一个可写或不可写值的属性

  存取描述符是由一对getter-setter函数功能来描述的属性

  描述符只能是以上两种之一,不可能同时拥有这两种。描述符属性包括:configurable(可配置性,这又为true时才能设置)、Writable(是否可写)、Enumerable(是否可枚举)、get(给属性提供getter)、setter(给属性提供setter)。看下这个例子:

 let obj = { name: 'vue' };
 // 数据描述符
 Object.defineProperty(obj,"age", {
     value: 11,
     writable: true,
     enumerable: true,
     configurable: true
 });

 // 数据存取符
 let objValue = { name: 'data' };
 Object.defineProperty(objValue, "age", {
     get: () => {
         console.log('getter');
         return objValue;
     },
     set: () => {
         console.log('setter');
     },
     enumerable: true,
     configurable: true
 });
 objValue.age = 18; // setter
 console.log(objValue.age); // getter

  前面已经提到了,数据描述符和存取描述符二者只能有一,虽然上诉几种属性二者均有,但是实际上writable不能和get、set同时存在。这就是Object.defineProperty方法的用法。

总结

  Vue通过Object.defineProperty()方法实现对数据的劫持,给每个实例数据添加了getter、setter,仅仅是这样还不能够实现数据的双向绑定。要实现双向绑定还需要对属性的get、set进行监听,还需要实现notify。也就是需要实现订阅器存放订阅者watcher,它可以将view和model数据联系起来,数据变化触发update更新视图。这就是数据双向绑定的大概思路。