Vue的响应式系统是Vue最有趣的特性之一。data只需要返回一个普通的文字对象,在运行时修改它的属性会引起接口更新。现在是数据驱动的界面开发。这样的设计对于程序员来说非常cool,重点只放在数据变化的逻辑上。而Vue将这个特性抽象成一个独立的观察者模块,可以单独使用。比如小程序开发框架Wepy就是利用这个模块来实现响应式的。这段时间看了Vue2.x中observer的源码。这里我也谈谈我对observer关键部分的设计和实现的理解。以下内容基于Vue2.x的源码分析。虽然已经有很多分析Vue响应式的文章,但希望我的理解也能对读者有所启发,吸取这些知识为己所用。如何跟踪数据变化?响应式的核心问题是:如何跟踪数据对象的属性变化?如果这是不可能的,或者编码体验对开发人员来说不好,那么响应式设计背后的道路并不平坦。这里的Vue2.x是基于Object.defineProperty,将这些属性全部用getter/setter包装起来,也就是劫持了对象属性的访问。这种实现对开发者来说基本上是完全不敏感的。下面我会摘取关键代码片段来说明它是如何实现的(假设我们设置的数据是一个普通的字面量对象),如果只是想学习设计思路,没有必要阅读完整的源码。首先,src/core/instance/state.js中有如下代码:functioninitData(vm:Component){//这个就是我们声明的data数据对象,vm就是Vue对象letdata=vm.$options.data//...//观察数据observe(data,true/*asRootData*/)}上面的代码是初始化Vue对象的数据,然后观察并设置数据对象。让我们跳到observe()部分:exportfunctionobserve(value:any,asRootData:?boolean):Observer|void{//...让ob:观察者|void//不用关注if(hasOwn(value,'__ob__')&&value.__ob__instanceofObserver){ob=value.__ob__}elseif(shouldObserve&&//这里有一堆条件,先不说注意...){//注意这里!ob=newObserver(value)}}这里有一个Observer类,传入的是value参数,就是我们设置的数据对象。下面介绍如何劫持属性访问的关键类。我们跳转到Observer的源码,在Observer的构造函数中会调用这么一段代码:exportclassObserver{//...constructor(value:any){//还是省略了很多代码...if(Array.isArray(value)){//暂时先不考虑Array}else{//看这里this.walk(value)}}}这里有个walk()方法,传数据in作为参数,让我们看看walk()是什么:walk(obj:Object){constkeys=Object.keys(obj)for(leti=0;i
