以前也用了一段時間Vue,對其用法也較爲熟練了,可是對各類用法和各類api使用都是隻知其然而不知其因此然。最近利用空閒時間嘗試的去看看Vue的源碼,以便更瞭解其具體原理實現,跟着學習學習。vue
傳的 data 進去的爲何能夠用this.xxx訪問,而不須要 this.data.xxx 呢?react
// vue\src\core\instance\state.js const sharedPropertyDefinition = { enumerable: true, configurable: true, get: noop, set: noop } export function proxy (target: Object, sourceKey: string, key: string) { sharedPropertyDefinition.get = function proxyGetter () { return this[sourceKey][key] } sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val } Object.defineProperty(target, key, sharedPropertyDefinition) } function initData (vm: Component) { let data = vm.$options.data //... const keys = Object.keys(data) //... let i = keys.length while (i--) { const key = keys[i] //.... proxy(vm, `_data`, key) } observe(data, true /* asRootData */) }
這段代碼看起來仍是很簡單的,將 data 中得 key 遍歷一遍,而後所有新增到實例上去,當咱們訪問修改 this.xxx 得時候,都是在訪問修改 this._data.xxxexpress
模塊源碼路徑 vue\src\core\observer
observer 模塊能夠說是 Vue 響應式得核心了,observer 模塊主要是 Observer、Dep、Watcher這三個部分了api
關係以下數組
-------get 收集依賴-------- ----------- 訂閱 ------------- | | | | | V | | ------------ ------------ ------------- | Obserser | ---- set ---->| Dep |------- 通知 ---->| Watcher | ------------ ------------ ------------- | update | ------------- | View | -------------
initData() 方法調用了 observe(data, true /* asRootData */) 先來看下這個方法函數
//對value 進行觀察處理 export function observe (value: any, asRootData: ?boolean): Observer | void { //判斷處理 value 必須是對象 而且不能是 VNode if (!isObject(value) || value instanceof VNode) { return } let ob: Observer | void if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__ } else if ( shouldObserve && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { ob = new Observer(value) } if (asRootData && ob) { ob.vmCount++ } return ob }
若是 data.__ob__ 已經存在直接返回,不然new一個新的 Observer 實例,下面是 Observer 類代碼oop
export class Observer { value: any; dep: Dep; vmCount: number; // number of vms that have this object as root $data constructor (value: any) { this.value = value // 這個dep 在 value 的屬性新增 刪除時候會用到 //value 若是是數組 也是經過 這裏的進行 依賴收集更新的 this.dep = new Dep() this.vmCount = 0 def(value, '__ob__', this) if (Array.isArray(value)) { //這裏是對數組原型對象 攔截 處理 if (hasProto) { protoAugment(value, arrayMethods) } else { copyAugment(value, arrayMethods, arrayKeys) } this.observeArray(value) } else { this.walk(value) } } walk (obj: Object) { const keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]) } } observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) } } }
在構造函數中,會給 value(data)增長 __ob__ (當前 Observer實例 ) 屬性。若是 value 是數組,會調用 observeArray 對數組進行遍歷,在調用 observe 方法對每一個元素進行觀察。若是是對象,調用 walk 遍歷 value 去調用 defineReactive 去修改屬性的 get/set。學習
//defineReactive 函數 export function defineReactive ( obj: Object, key: string, //遍歷的key val: any, customSetter?: ?Function, shallow?: boolean ) { const dep = new 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) { val = obj[key] } //若是 key 的值是 對象 的話,對其 value 也會進行響應處理 let childOb = !shallow && observe(val) //爲當前 key 添加get/set Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { const value = getter ? getter.call(obj) : val if (Dep.target) { dep.depend() //對當前屬性 進行依賴收集 if (childOb) { //若是屬性值是 對象 ,則對屬性值自己進行依賴收集 childOb.dep.depend() if (Array.isArray(value)) { //若是值是數組 對數組的每一個元素進行依賴收集 dependArray(value) } } } return value }, set: function reactiveSetter (newVal) { const value = getter ? getter.call(obj) : val if (newVal === value || (newVal !== newVal && value !== value)) { return } if (getter && !setter) return if (setter) { setter.call(obj, newVal) } else { val = newVal } //對新值 進行觀察處理 childOb = !shallow && observe(newVal) //通知 Watcher dep.notify() } }) } 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() if (Array.isArray(e)) { dependArray(e) } } }
上面有兩個地方有存在 Depui
Dep 是 Observer 與 Watcher 橋樑,也能夠認爲Dep是服務於Observer的訂閱系統。Watcher訂閱某個Observer的Dep,當Observer觀察的數據發生變化時,經過Dep通知各個已經訂閱的Watcher。this
export default class Dep { static target: ?Watcher; id: number; subs: Array<Watcher>; constructor () { this.id = uid++ this.subs = [] //Watcher實例 } //接收的參數爲Watcher實例,並把Watcher實例存入記錄依賴的數組中 addSub (sub: Watcher) { this.subs.push(sub) } //與addSub對應,做用是將Watcher實例從記錄依賴的數組中移除 removeSub (sub: Watcher) { remove(this.subs, sub) } //依賴收集 depend () { if (Dep.target) { //存放當前Wather實例 //將當前 Dep 存放到 Watcher(觀察者) 中的依賴中 Dep.target.addDep(this) } } //通知依賴數組中全部的watcher進行更新操做 notify () { const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } } Dep.target = null const targetStack = [] export function pushTarget (target: ?Watcher) { targetStack.push(target) Dep.target = target } export function popTarget () { targetStack.pop() Dep.target = targetStack[targetStack.length - 1] }
先看 Watcher 的構造函數
constructor( vm: Component, expOrFn: string | Function, cb: Function, options?: ?Object, isRenderWatcher?: boolean) { ... if (typeof expOrFn === 'function') { this.getter = expOrFn } else { this.getter = parsePath(expOrFn) if (!this.getter) { this.getter = noop } } this.value = this.lazy ? undefined : this.get() }
expOrFn,對於初始化用來渲染視圖的 watcher 來講,就是render方法,對於computed來講就是表達式,對於watch纔是key,而getter方法是用來取value的。最後調用了get()方法
get () { //將Dep.target設置爲當前watcher實例 pushTarget(this) let value const vm = this.vm try { // 執行一次get 收集依賴 value = this.getter.call(vm, vm) } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "${this.expression}"`) } else { throw e } } finally { if (this.deep) { traverse(value) } popTarget() this.cleanupDeps() //清楚依賴 } return value }
假如當前Watcher實例中 getter 是 render,當render遇到模板中的{{xxx}}表達式的時候,就是去讀取 data.xxx,這個時候就觸發 data.xxx 的 get方法,這個時候 get 中會執行Dep.depend(),而此時 Dep.target 就是當前 watcher ,而後調用 watcher.addDep()。也就將data.xxx 與 當前watcher 關聯起來了
//watcher 的其餘方法 //接收參數dep(Dep實例),讓當前watcher訂閱dep addDep (dep: Dep) { const id = dep.id if (!this.newDepIds.has(id)) { this.newDepIds.add(id) this.newDeps.push(dep) if (!this.depIds.has(id)) { //將watcher實例 也添加到 Dep實例中 dep.addSub(this) } } } //清楚對dep的訂閱信息 cleanupDeps () { } //馬上運行watcher或者將watcher加入隊列中 update () { if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queueWatcher(this) } } //運行watcher,調用this.get()求值,而後觸發回調 run () { if (this.active) { const value = this.get() if ( value !== this.value || isObject(value) || this.deep ) { const oldValue = this.value this.value = value if (this.user) { try { this.cb.call(this.vm, value, oldValue) } catch (e) { handleError(e, this.vm, `callback for watcher "${this.expression}"`) } } else { this.cb.call(this.vm, value, oldValue) } } } } //調用this.get()求值 evaluate () { this.value = this.get() this.dirty = false } //遍歷this.deps,讓當前watcher實例訂閱全部dep depend () { let i = this.deps.length while (i--) { this.deps[i].depend() } } //去除當前watcher實例全部的訂閱 teardown () { if (this.active) { if (!this.vm._isBeingDestroyed) { remove(this.vm._watchers, this) } let i = this.deps.length while (i--) { this.deps[i].removeSub(this) } this.active = false } }