這是我本身在深刻了解 Vue
過程本身思考過的一些問題,特地拿出來記錄一下,以避免從此遺忘:vue
Vue
把數據轉換成響應式數據後,是怎麼來觸發getter從而收集依賴的解答:Vue
在初始化的過程當中,把數據都轉換成響應式數據。在觸發生命週期函數beforeMount
以後經過new Watcher()
來觀測渲染函數。源碼git
解答:Vue
中數組和對象收集依賴都是在getter
中收集。可是觸發setter
的地方不同。github
由於Vue
監聽數組的變化是經過Array
的原型方法來監聽的,因此必需要保證能在原型方法和getter
中都可以獲取到 dep ,因此把 dep 保存在 Observer
實例上。(具體的解釋請看響應式原理)express
Watcher
監聽函數怎麼監測函數中全部用到的數據的解答:當用 Watcher
監聽一個函數時,函數裏面每個數據的getter都會觸發,而且此時的 Dep.target
是當前的 Watcher
實例,因此每個數據都會把當前的Watcher
實例收集起來。數組
Watcher
監聽一個路徑字符串:'a.b.c',會分別監聽a、a.b、a.b.c嗎解答:會。由於a、a.b、a.b.c的getter都會觸發。函數
解答:當數據變更後確定會從新觸發getter。源碼this
// Watcher.js
get () {
pushTarget(this)
let value
const vm = this.vm
try {
// 這裏觸發getter
value = this.getter.call(vm, vm)
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value)
}
popTarget()
// 這裏清理多餘的依賴
this.cleanupDeps()
}
return value
}
cleanupDeps () {
let i = this.deps.length
while (i--) {
const dep = this.deps[i]
if (!this.newDepIds.has(dep.id)) {
dep.removeSub(this)
}
}
let tmp = this.depIds
this.depIds = this.newDepIds
this.newDepIds = tmp
this.newDepIds.clear()
tmp = this.deps
this.deps = this.newDeps
this.newDeps = tmp
this.newDeps.length = 0
}
複製代碼