最近在學習Vue的源碼,看了網上一些大神的博客,看起來感受仍是蠻吃力的。本身記錄一下學習的理解,但願可以達到簡單易懂,不看源碼也能理解的效果😆javascript
若是有錯誤,懇求大佬們指點嘿😋html
相信不少同窗或多或少都瞭解Vue的響應式原理是經過Object.defineProperty
實現的。被Object.defineProperty
綁定過的對象,會變成「響應式」化。也就是改變這個對象的時候會觸發get和set事件。進而觸發一些視圖更新。舉個栗子🌰vue
function defineReactive (obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: () => {
console.log('我被讀了,我要不要作點什麼好?');
return val;
},
set: newVal => {
if (val === newVal) {
return;
}
val = newVal;
console.log("數據被改變了,我要把新的值渲染到頁面上去!");
}
})
}
let data = {
text: 'hello world',
};
// 對data上的text屬性進行綁定
defineReactive(data, 'text', data.text);
console.log(data.text); // 控制檯輸出 <我被讀了,我要不要作點什麼好?>
data.text = 'hello Vue'; // 控制檯輸出 <hello Vue && 數據被改變了,我要把新的值渲染到頁面上去!>
複製代碼
Vue
中用Observer
類來管理上述響應式化Object.defineProperty
的過程。咱們能夠用以下代碼來描述,將this.data
也就是咱們在Vue
代碼中定義的data
屬性所有進行「響應式」綁定。java
class Observer {
constructor() {
// 響應式綁定數據經過方法
observe(this.data);
}
}
export function observe (data) {
const keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
// 將data中咱們定義的每一個屬性進行響應式綁定
defineReactive(obj, keys[i]);
}
}
複製代碼
相信沒有看過源碼或者剛接觸Dep
這個詞的同窗都會比較懵。那Dep
到底是用來作什麼的呢? 咱們經過defineReactive
方法將data
中的數據進行響應式後,雖然能夠監聽到數據的變化了,那咱們怎麼處理通知視圖就更新呢?git
Dep
就是幫咱們收集【究竟要通知到哪裏的】。好比下面的代碼案例,咱們發現,雖然data
中有text
和message
屬性,可是隻有message
被渲染到頁面上,至於text
不管怎麼變化都影響不到視圖的展現,所以咱們僅僅對message
進行收集便可,能夠避免一些無用的工做。github
那這個時候message
的Dep
就收集到了一個依賴,這個依賴就是用來管理data
中message
變化的。異步
<div>
<p>{{message}}</p>
</div>
複製代碼
data: {
text: 'hello world',
message: 'hello vue',
}
複製代碼
當使用watch
屬性時,也就是開發者自定義的監聽某個data中屬性的變化。好比監聽message
的變化,message
變化時咱們就要通知到watch
這個鉤子,讓它去執行回調函數。函數
這個時候message
的Dep
就收集到了兩個依賴,第二個依賴就是用來管理watch
中message
變化的。post
watch: {
message: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
}
複製代碼
當開發者自定義computed
計算屬性時,以下messageT
屬性,是依賴message
的變化的。所以message
變化時咱們也要通知到computed
,讓它去執行回調函數。 這個時候message
的Dep
就收集到了三個依賴,這個依賴就是用來管理computed
中message
變化的。學習
computed: {
messageT() {
return this.message + '!';
}
}
複製代碼
圖示以下:一個屬性可能有多個依賴,每一個響應式數據都有一個Dep
來管理它的依賴。
咱們如何知道data
中的某個屬性被使用了,答案就是Object.defineProperty
,由於讀取某個屬性就會觸發get
方法。能夠將代碼進行以下改造:
function defineReactive (obj, key, val) {
let Dep; // 依賴
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: () => {
console.log('我被讀了,我要不要作點什麼好?');
// 被讀取了,將這個依賴收集起來
Dep.depend(); // 本次新增
return val;
},
set: newVal => {
if (val === newVal) {
return;
}
val = newVal;
// 被改變了,通知依賴去更新
Dep.notify(); // 本次新增
console.log("數據被改變了,我要把新的值渲染到頁面上去!");
}
})
}
複製代碼
那所謂的依賴到底是什麼呢?上面的圖中已經暴露了答案,就是Watcher
。
Watcher
就是相似中介的角色,好比message
就有三個中介,當message
變化,就通知這三個中介,他們就去執行各自須要作的變化。
Watcher
可以控制本身屬於哪一個,是data
中的屬性的仍是watch
,或者是computed
,Watcher
本身有統一的更新入口,只要你通知它,就會執行對應的更新方法。
所以咱們能夠推測出,Watcher
必需要有的2個方法。一個就是通知變化,另外一個就是被收集起來到Dep中去。
class Watcher {
addDep() {
// 我這個Watcher要被塞到Dep裏去了~~
},
update() {
// Dep通知我更新呢~~
},
}
複製代碼
回顧一下,Vue
響應式原理的核心就是Observer
、Dep
、Watcher
。
Observer
中進行響應式的綁定,在數據被讀的時候,觸發get
方法,執行Dep
來收集依賴,也就是收集Watcher
。
在數據被改的時候,觸發set
方法,經過對應的全部依賴(Watcher
),去執行更新。好比watch
和computed
就執行開發者自定義的回調方法。
本篇文章屬於入門篇,可以先簡單的理解Observer
、Dep
、Watcher
三者的做用和關係。後面會逐漸詳細和深刻,按部就班的理解和學習。
若是你以爲對你有幫助,就點個贊吧~
正在書寫的系列~
Github博客 歡迎交流~