详解Vue数据驱动原理(2)

export class Observer { value: any; // 观察的数据 dep: Dep; // dep实例用于 派发更新 vmCount: number; // number of vms that have this object as root $data constructor (value: any) { this.value = value this.dep = new Dep() this.vmCount = 0 // 把__ob__变成不可枚举的,因为没有必要改变watcher本身 def(value, '__ob__', this) 会执行 value._ob_ = this(watcher实例)操作 if (Array.isArray(value)) { // 当value是数组 if (hasProto) { protoAugment(value, arrayMethods) // 重写Array.prototype的相关方法 } else { copyAugment(value, arrayMethods, arrayKeys) // 重写Array.prototype的相关方法 } this.observeArray(value) } else { this.walk(value) // 当value为对象 } } /** * Walk through all properties and convert them into * getter/setters. This method should only be called when * value type is Object. */ walk (obj: Object) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) // 对数据进行响应式处理 } } /** * Observe a list of Array items. */ observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) // 遍历value数组的每一项并调用observe函数,进行响应式处理 } } }

Observe类要做的事情通过查看源码也是清晰明了,对数据进行响应式处理,并对数组的原型方法进行重写!defineReactive函数就是实现依赖收集和派发更新的核心函数了,实现代码如下。

依赖收集

defineReactive

export function defineReactive ( obj: Object, // data数据 key: string, // data中对应的key值 val: any, // 给data[key] 赋值 可选 customSetter?: ?Function, // 自定义setter 可选 shallow?: boolean // 是否对data[key]为对象的值进行observe递归 可选 ) { const dep = new Dep() // Dep实例 **每一个key对应一个Dep实例** const property = Object.getOwnPropertyDescriptor(obj, key) // 拿到对象的属性描述 if (property && property.configurable === false) { // 判断对象是否可配置 return } // cater for pre-defined getter/setters const getter = property && property.get const setter = property && property.set if ((!getter || setter) && arguments.length === 2) { // 没有getter或者有setter,并且传入的参数有两个 val = obj[key] } let childOb = !shallow && observe(val) // 根据shallow,递归遍历val对象,相当于val当做data传入 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { const value = getter ? getter.call(obj) : val if (Dep.target) { // 当前的全部的Watcher实例 dep.depend() // 把当前的Dep.target加入到dep.subs数组中 if (childOb) { // 如果val是对象, childOb.dep.depend() // 会在value._ob_的dep.subs数组中加入Dep.target, 忘记ob实例属性的同学可往回翻一番 if (Array.isArray(value)) { dependArray(value) // 定义如下,逻辑也比较简单 } } } return value }, set: function reactiveSetter (newVal) { // .... } }) } function dependArray (value: Array<any>) { for (let e, i = 0, l = value.length; i < l; i++) { e = value[i] e && e.__ob__ && e.__ob__.dep.depend() // 如果e是响应式数据,则往e._ob_.dep.subs数组中加入Dep.target if (Array.isArray(e)) { dependArray(e) // 递归遍历 } } }

代码中多次用到了Dep类和Dep.target,理解清楚了它们的作用,我们就离Vue数据驱动的原理更近一步了,相关的代码如下:

Dep

let uid = 0 /** * A dep is an observable that can have multiple * directives subscribing to it. */ export default class Dep { static target: ?Watcher; id: number; subs: Array<Watcher>; constructor () { this.id = uid++ // 每一个dep都有一个唯一的ID this.subs = [] // 存放watcher实例的数组 } addSub (sub: Watcher) { this.subs.push(sub) // 往this.subs加入watcher } removeSub (sub: Watcher) { remove(this.subs, sub) // 删除this.subs对应的watcher } depend () { if (Dep.target) { // watcher.addDep(this) actually Dep.target.addDep(this) // 在watcher类中查看 } } notify () { // stabilize the subscriber list first const subs = this.subs.slice() if (process.env.NODE_ENV !== 'production' && !config.async) { // subs aren't sorted in scheduler if not running async // we need to sort them now to make sure they fire in correct // order subs.sort((a, b) => a.id - b.id) // 根据watcher的id进行排序 } for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() // 遍历subs数组中的每一个watcher执行update方法 } } } // The current target watcher being evaluated. // This is globally unique because only one watcher // can be evaluated at a time. Dep.target = null // Dep.target 代表当前全局的watcher const targetStack = [] export function pushTarget (target: ?Watcher) { targetStack.push(target) Dep.target = target // 赋值 } export function popTarget () { targetStack.pop() Dep.target = targetStack[targetStack.length - 1] // 赋值 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/a607475bfa315823449a2e66cbf58e9f.html