vue3.0發(fā)布了,回顧一波2.x原理
vue 2.x 響應(yīng)式原理
image
主要做了這么幾件事:數(shù)據(jù)劫持棚辽、收集依賴苍息、派發(fā)更新
- 數(shù)據(jù)劫持:new Vue的時候遍歷data對象疾渴,用Object.defineProperty給所有屬性加上了getter和setter
- 依賴的收集:render的過程穿稳,會觸發(fā)數(shù)據(jù)的getter存皂,在getter的時候把當(dāng)前的watcher對象收集起來
- 派發(fā)更新:setter的時候,遍歷這個數(shù)據(jù)的依賴對象(watcher對象)逢艘,進(jìn)行更新
數(shù)據(jù)劫持
通過Object.defineProperty劫持對象屬性,讓數(shù)據(jù)變?yōu)槭强捎^察的
class Vue {
constructor(options) {
observer(options.data);
}
observer(value) {
if (!value || (typeof value !== 'object')) {
return;
}
// 遍歷data對象 逐個加上getter setter
Object.keys(value).forEach(key => defineReactive(value, key, value[key]));
}
defineReactive(obj, key, val) {
const dep = new Dep(); // Dep是依賴收集類
Object.defineProperty(obj, key, {
enumerable: true, // 屬性可枚舉
configurable: true //屬性可被修改或刪除
get() {
dep.addSub(Dep.target); // 依賴采集
return val;
},
set(newVal) {
if (newVal === val) return;
dep.notify(newVal); // 派發(fā)更新
}
})
}
}
可以看到主要就是這個defineReactive函數(shù)骤菠,他利用Object.defineProperty實(shí)現(xiàn)了數(shù)據(jù)劫持
依賴收集&派發(fā)更新
那么vue是怎么知道當(dāng)數(shù)據(jù)改變的時候都要去通知誰呢它改?它用了一個訂閱者Dep,它用來存放我們的觀察者對象商乎,當(dāng)數(shù)據(jù)發(fā)生改變央拖,就通知觀察者,觀察者通過調(diào)用自己的update方法完成更新鹉戚。
<!--訂閱者Dep類-->
class Dep {
constructor () {
this.newDeps = [] // 用來存放我們的依賴對象(也即觀察者)
}
addDep (watcher) {
this.newDeps.push(watcher) // 向隊(duì)列里新加一下watcher對象
}
update () {
this.newDeps.forEach((sub) => {
sub.update(); // 遍歷watcher進(jìn)行更新
})
}
}
<!--觀察者Watcher類-->
class Watcher {
constructor () {
Dep.target = this // new Watcher的時候把觀察者存放到Dep.target里面
}
update () {
console.log("視圖更新啦~"); // 更新視圖
<!--queueWatcher(this) 異步更新策略 后面再寫一篇介紹 -->
}
}
new一個Watcher對象鲜戒,此時它會指向Dep.target,在render過程觸發(fā)getter抹凳,把Dep.target添加到依賴隊(duì)列遏餐。這樣便完成了依賴的收集。數(shù)據(jù)改變赢底,通知依賴進(jìn)行update操作失都。
image
以上代碼是2.x版本響應(yīng)式原理的代碼模擬柏蘑,在vue中這幾個類都是單獨(dú)的文件,源碼地址粹庞。
另外vue對數(shù)組做了特殊處理咳焚,數(shù)組的響應(yīng)式原理我補(bǔ)充在了另一篇文章里vue響應(yīng)式原理-數(shù)組篇
last but not least, 老鐵請留步,點(diǎn)個贊再走~??