前言
一個多月前,抽空看了一下 Vue 2.0 的源碼,看源碼最好的方式還是先搜下相關文章,把握整體脈絡之后,再看一些細節。先列一下我看源碼時候參考的一些文章:
這幾篇文章都寫得很好,但也有一些缺點。其中《vue源碼解析系列》雖然講得比較深入,但想要讀懂,必須對源碼有一定了解;而其他兩篇文章雖然易懂,但是又不夠深入。
所以我又參照了 Vue 源碼,實現了一個簡易的 miniVue。
原本計劃在這個基礎上,寫一篇《一步步實現 miniVue》的文章,但是后來因為工作忙的原因,一直沒有動筆。
所以現在先寫一篇碎碎念,記下一些 Vue 設計上的黑魔法,以及個人對 Vue 2.0 代碼的一些觀點,算是一篇草稿吧。
正文
- Vue 設計上用了許多黑魔法,其中最廣為人知的就是利用 JavaScript 中的 getter,setter 實現一套雙向綁定機制。雖然這一套機制非常精巧,但是這種對原生語言的 hack 也導致了代碼的不容易理解。比如對一個對象的訪問,可能也會導致 watcher.addDep 的觸發,而這是在代碼層面上很難察覺的,而這種地方,也很容易引入 bug。
- 但還是不得不說,Observer-Watcher 中的代碼,是 Vue 里面寫得最漂亮的代碼之一(另一個是 patch)。其中 watcher 里面,利用 deps,newDeps 兩個數組,實現了 update Deps 的功能,具體的代碼在 Watcher.addDep 中。雖然只有幾行代碼,但是卻使用了垃圾回收的原理,非常優雅。
- Patch 是 Vue 實現虛擬 DOM 的一個重要部分,如果有看過源碼注釋的話,就會發現這個 patch 實際上是基于另一個項目修改而來的。Patch 里面的 updateChildren 是最重要的函數,巧妙且大膽地動態去修改 Vnode數組(同時也修改了 Vnode),從而讓 diff 和 patch 同時完成。相比之下,React 的實現就沒有那么巧妙了,只是簡單地用了最基本的 diff 套路,對 vNode 進行靜態分析(當然這只是很久之前我所看到的 React 版本,可能現在已經改變了實現方式)。
- 在閱讀 React 和 Vue 的源碼時,都需要分清一個比較容易混淆的概念,那就是 Component 和 componentInstance,這兩者之間的關系就和面向對象中的 Class 和 Object 的關系類似。Vue 的 Component機制原理上和 React 是一樣的。其中在 Vue 中,Vue.component 實際上是 Vue 的一個子類,這也算是一個設計比較巧妙的地方吧,不過也是情理之中。
- computed 的實現算是把 Observer-Watcher 用到了極致,其中的關鍵在于理解 createComputedGetter 函數,通過 watcher.depend() 將綁定在 watcher 中的 deps 都綁定到 Dep.target 中。雖然代碼量很少,但是這段代碼依然很難理解,這也算是檢驗是否真正理解 Observer-Watcher 機制的一個判斷方法吧。