Vue学习系列一 —— MVVM响应式系统的基本实现原理

MVVM是什么

MVVM是Model-View-ViewModel的简写。它模式是MVC—>MVP—>MVVM的进化版。
Model负责用JavaScript对象表示,View负责UI界面显示,两者做到了最大限度的分离。
而把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的界面修改同步回Model更新数据。

主流MVVM框架和实现做法

  • 脏值检查(angular.js)
  • 发布者-订阅者模式+数据劫持(vue.js)

脏值检查: angular.js 是通过脏值检测的方式来比对数据是否有变更而决定是否更新视图。
原理是,拷贝一份copy_viewModel在内存中,用户操作导致viewModel发生改变的行为时,框架都会把copy_viewModel和最新的viewModel进行深度比较,一旦发现有属性发生变化,则重新渲染与之绑定的DOM节点。
最简单的方式就是通过setInterval()定时轮询检测数据变动,angular触发时进入脏值检测。但只限 指定的事件 (如:用户点击,输入操作,ajax请求,setInterval,setTimeout等...),否则需手动调用apply函数去强制执行一次脏检查。

数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter在数据变动时发布消息给订阅者,触发相应的监听回调,而产生更新数据和视图。

vue数据双向绑定原理

Vue学习系列一 —— MVVM响应式系统的基本实现原理_第1张图片
官网数据绑定说明图

原理图告诉我们,data属性定义了getter、setter对属性进行劫持,当属性值改变是就会notify通知watch对象,而watch对象则会重新触发组件呈现功能,继而更新view上的DOM节点树。
反之,view上输入数据时,也会触发data变更,也会触发订阅者watch更新,这样子model数据就可以实时更新view上的数据变化。这样一个过程就是vue的数据双向绑定了。

vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的。

Object.defineProperty

Object.defineProperty是ES5一个方法,可以直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并返回这个对象,对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符
数据描述符是一个拥有可写或不可写值的属性。
存取描述符是由一对getter-setter函数功能来描述的属性。
描述符必须是两种形式之一;不能同时是两者。即:有值和可写,或者可get和set
属性描述符包括:

  • Configurable(可配置性相当于属性的总开关,只有为true时才能设置,而且不可逆)、
  • Enumerable(是否可枚举,为false时for..in以及Object.keys()将不能枚举出该属性)、
  • Writable(是否可写,为false时将不能够修改属性的值)、
  • Value(属性的值,默认为undefined)、
  • Get(一个给属性提供getter的方法)、
  • Set(一个给属性提供setter的方法)、
var Book = {}
Object.defineProperty(Book, 'name', {
  get: function () {
    return '《' + name + '》'
  },
  set: function (value) {
    name = value;
    console.log('你取了一个书名叫做' + value);
  }
})

console.log(Book.name);  // 《》
Book.name = 'vue权威指南';  // 你取了一个书名叫做vue权威指南
console.log(Book.name);  // 《vue权威指南》

实现过程

我们已经知道怎么实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
因此接下去我们执行以下4个步骤,实现数据的双向绑定:

  1. 实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就拿到最新值并通知订阅者。
  2. 实现一个订阅者Watcher,连接ObserverCompile。可以订阅并收到每个属性的变化通知并执行指令绑定的相应函数,从而更新视图。
  3. 实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板替换数据,以及绑定相应的更新函数。
  4. mvvm入口函数,整合以上三者。




    
    
    
    Document



    

{{title}}

{{name}}

aaaa{{xxx}}zzzz

参考链接:

深入响应式原理
剖析Vue原理&实现双向绑定MVVM
《响应式系统的基本原理》.js
JavaScript实现MVVM之我就是想监测一个普通对象的变化

你可能感兴趣的:(Vue学习系列一 —— MVVM响应式系统的基本实现原理)