Vue 2 的雙向綁定原理基于?Object.defineProperty,核心源碼在?src/core/observer
?目錄中。
1. 核心模塊:observer
observer
?模塊負責將普通對象轉換為響應式對象,主要包括以下文件:
index.js
:定義?Observer
?類,用于將對象轉換為響應式。dep.js
:定義?Dep
?類,用于管理依賴(訂閱者)。watcher.js
:定義?Watcher
?類,用于監聽數據變化并觸發更新。
2.?Observer
?類
Observer
?類是 Vue 2 響應式系統的核心,它通過?Object.defineProperty
?將對象的屬性轉換為?getter
?和?setter
,從而實現依賴收集和派發更新。
源碼位置:src/core/observer/index.js
export class Observer {value: any;dep: Dep;vmCount: number;constructor(value: any) {this.value = value;this.dep = new Dep();this.vmCount = 0;def(value, '__ob__', this); // 將 Observer 實例掛載到對象的 __ob__ 屬性上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]);}}
}
Observer
?類會遞歸地將對象的屬性轉換為響應式。- 對于數組,Vue 2 通過重寫數組的變異方法(如?
push
、pop
?等)來實現響應式。
3.?defineReactive
?函數
defineReactive
?是 Vue 2 實現響應式的核心函數,它通過?Object.defineProperty
?定義屬性的?getter
?和?setter
。
源碼位置:src/core/observer/index.js
export function defineReactive(obj: Object,key: string,val: any,customSetter?: ?Function,shallow?: boolean
) {const dep = new Dep(); // 每個屬性都有一個 Dep 實例,用于管理依賴const getter = property && property.get;const setter = property && property.set;if ((!getter || setter) && arguments.length === 2) {val = obj[key];}let childOb = !shallow && observe(val); // 遞歸處理嵌套對象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 (setter) {setter.call(obj, newVal);} else {val = newVal;}childOb = !shallow && observe(newVal); // 對新值進行響應式處理dep.notify(); // 通知依賴更新},});
}
getter
:在訪問屬性時,調用?dep.depend()
?收集依賴。setter
:在修改屬性時,調用?dep.notify()
?通知依賴更新。
4.?Dep
?類
Dep
?類是依賴管理器,用于存儲和管理?Watcher
?實例。
源碼位置:src/core/observer/dep.js
export default class Dep {static target: ?Watcher;id: number;subs: Array<Watcher>;constructor() {this.id = uid++;this.subs = [];}addSub(sub: Watcher) {this.subs.push(sub);}removeSub(sub: Watcher) {remove(this.subs, sub);}depend() {if (Dep.target) {Dep.target.addDep(this);}}notify() {const subs = this.subs.slice();for (let i = 0, l = subs.length; i < l; i++) {subs[i].update();}}
}
Dep.target
:當前正在計算的?Watcher
?實例。subs
:存儲所有訂閱了該屬性的?Watcher
?實例。notify
:通知所有訂閱者更新。
5.?Watcher
?類
Watcher
?類是 Vue 2 中用于監聽數據變化的訂閱者,它會在數據變化時觸發回調函數。
源碼位置:src/core/observer/watcher.js
export default class Watcher {vm: Component;expression: string;cb: Function;id: number;deps: Array<Dep>;newDeps: Array<Dep>;depIds: SimpleSet;newDepIds: SimpleSet;getter: Function;value: any;constructor(vm: Component,expOrFn: string | Function,cb: Function,options?: ?Object,isRenderWatcher?: boolean) {this.vm = vm;this.cb = cb;this.id = ++uid; // uid for batchingthis.deps = [];this.newDeps = [];this.depIds = new Set();this.newDepIds = new Set();this.getter = parsePath(expOrFn);this.value = this.get();}get() {pushTarget(this); // 將當前 Watcher 設置為 Dep.targetlet value;const vm = this.vm;try {value = this.getter.call(vm, vm);} catch (e) {// 處理錯誤} finally {popTarget(); // 恢復之前的 Watcherthis.cleanupDeps();}return value;}update() {queueWatcher(this); // 將 Watcher 加入隊列,等待批量更新}run() {const value = this.get();if (value !== this.value || isObject(value)) {const oldValue = this.value;this.value = value;this.cb.call(this.vm, value, oldValue); // 執行回調}}
}
Watcher
?實例會在初始化時調用?get
?方法,觸發屬性的?getter
,從而收集依賴。- 當數據變化時,
Watcher
?的?update
?方法會被調用,最終觸發回調函數。
Vue 2 的雙向綁定原理基于?Object.defineProperty
,通過以下步驟實現:
- 響應式化:
Observer
?類將對象的屬性轉換為?getter
?和?setter
。 - 依賴收集:在?
getter
?中調用?dep.depend()
,將當前?Watcher
?添加到依賴列表中。 - 派發更新:在?
setter
?中調用?dep.notify()
,通知所有依賴的?Watcher
?更新。 - 批量更新:
Watcher
?的更新會被加入隊列,異步執行,以提高性能。