学了一小段时间的Vue,之前多多少少有了解一些它的原理,但是一直没能有机会梳理一遍。而且之前在面试中也被问到过,才发现自己居然说不出来。因此这样让我下定决心自己按照Vue的原理实现一遍简单的MVVM框架。
本文实现除了参考官方源码Vuejs,还参考开源仓库,在此做出说明。
响应式原理
把一个普通JavaScript对象传给Vue实例的data选项,Vue将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter。Object.defineProperty 是仅ES5支持,且无法shim的特性,这也就是为什么Vue不支持IE8以及更低版本浏览器的原因
Vue.js是采用Object.defineProperty
的getter
和setter
,也叫数据劫持,并结合观察者模式来实现数据绑定的。
- Observer数据监听器,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者,内部采用Object.defineProperty的getter和setter来实现。
- Compile指令解析器,它的作用对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。
- Watcher订阅者, 作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。
- Dep消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify函数,再调用订阅者的update方法。
实现
Observer
首先我们使用ES5的Object.defineProperty
来实现属性的监听。对要绑定的data
对象的属性依次设置getter
和setter
。data
子属性也需要监听。
|
|
我们监听如下data
对象,一切都很好,但是使用Array的push等方法并不会被监听到。
|
|
为了实现监听数组,我们自然要改写操作数组的方法,但是又不能改写原生Array原型中的方法。简单的方法是使用Object.create
继承Array的原型创建一个新对象arrFakeProto
,用这个对象替换需要监听的数组的原型。
看看操作数组的监听效果
看起来达到预期效果了,但是这里其实还有一个小问题,那就是我们使用push
操作数组,监听到变化了,但是新元素并没有被监听到。因此对于添加操作push
、unshifit
、splice
添加的新元素需要重新监听。
综上,我们得到完整的observe代码
以上代码中,array和object分开监听,实际上只监听object,array只监听数组操作方法,不再监听下标,但是新添加的元素如果是对象依然进行监听
Dep
至此,简单的监听已经实现了,但是还需要做一件事情,那就是在监听到变化后通知订阅者Watcher
,因此还需要实现上文说的消息订阅器Dep。消息订阅器实质上在内部维护一个数组,用来收集订阅者(Watcher),当Observer监听数据变动后(在set中触发),(在set中)触发notify函数,再调用订阅者的update方法。
未完,待续。。。。