
— Object.defineProperty, and some notes.
Vue 組件在初始化時會將 props, data…等屬性進行綁定,並監聽他們的變化,而後在該值對應的模板上執行渲染。比如:
其實 Vue 是利用了ES5標準下的 Object.defineProperty 來將 props, data… 轉變為響應式物件的。
Object.defineProperty(object, prop, descriptor)其中 descriptor 的部分可以為 object 中的 prop 提供 get(getter), set(setter)的屬性方法,用於取值及賦值時的操作:
obj.a
// gotcha!
// 10obj.a = 12;
obj.a
// gotcha!
// 13
以上是對範例中 obj 簡單操作的結果,透過 setter 及 getter 我們可以在取賦值時增加一些額外的操作。熟悉 Vue 開發的人應該也不難發現,這樣的操作其實跟 Vue 的 computed getter/setter 寫法是異曲同工的。
瞭解上述的方法後,就來看看 Vue 的原始碼中是如何將物件轉換成響應式對象的吧!我們可以從 GitHub 上找到 Vue,而相關檔案都會在 src/ 路徑底下。
首先來了解一下 Vue 程式的初始化流程,通常我們會在 index.js 中執行 new Vue() ,這個步驟藉由一個 Vue 的 Class 創建出 Vue 的 instance,並執行 this._init() 這個 Function。於 src/core/instance/index.js 中可以找到它:
而 _init 會處理 Vue 的生命週期、事件、data、props 等初始化的設定,相關原始碼在 src/core/instance/init.js 。其中將資料物件轉變為響應式的關鍵涵式為 initState() ,由 src/core/instance/state.js 中可以他執行了多個初始化的動作,包含 initProps initData initComputed 等等。
這次我們先專注initProps ,他在遍歷了所有的 props 後執行了涵式defineReactive ,下面節錄原始碼中比較重要的部分:
到了這裡,總算可以在 src/core/observer/index.js 中看到 defineReactive 實際使用了 Object.defineProperty 對傳入的參數進行 getter/setter 的設置:
探究原始碼的過程著實令人心累,且 vue 3.0 推出在即,但已趨成熟的 Vue 2真的很適合拿來研讀,在其中也能夠發現許多有趣的方法,以及恍然大悟的心情,甚至能夠讓自己寫 code 的能力加以提升!這次只關注在響應式的入門,有機會再來一一探索如 virtul dom 等核心的部分吧。
