Vue框架通過其響應式系統來監聽對象和數組的變化。這個系統的核心在于追蹤依賴關系,并在數據變化時通知所有依賴于該數據的觀察者。
?
1. 對象監聽
Vue使用`Object.defineProperty`方法來劫持各個屬性的getter和setter。當組件中的數據被讀取時,會觸發getter函數,在getter函數內部進行依賴收集;當數據被修改時,setter函數會被觸發,進而通知所有依賴于該屬性的觀察者進行更新。這種方式使得Vue可以精確地跟蹤每個屬性的變化,并進行高效的更新,還可以使用Object.assign()直接賦值來替換整個對象,可以觸發視圖更新。
2. 數組監聽
由于JavaScript的原生數組方法(如`push`、`pop`、`splice`等)不會觸發`Object.defineProperty`中的setter,Vue對數組的原生方法進行了重寫,使其也可以觸發視圖更新。另外,Vue還提供了`Vue.set`方法或`Array.prototype.splice`來確保新增的元素也是響應式的。對于刪除操作,Vue會通過索引跟蹤依賴,確保刪除操作能夠被監聽到。
3. 依賴收集
在組件渲染過程中,如果一個數據被讀取,那么這個數據就會被添加到這個組件的依賴列表中。當數據發生變化時,Vue會遍歷這個依賴列表,并通知所有依賴這個數據的部分進行更新。
4. Watcher
Vue的內部機制創建了Watcher對象,這些對象負責追蹤自己依賴的數據,并在數據變化時執行回調函數以更新視圖。每個組件實例都有一個Watcher實例與之對應,用于監聽該組件模板所依賴的數據。
5. 異步隊列
為了優化性能,Vue還會將這些更新放入一個異步隊列,然后使用`nextTick`方法將這些更新在下一個DOM循環中一次性應用,這樣可以減少不必要的DOM操作,提高渲染效率。
6. 虛擬DOM(VDOM)
Vue使用虛擬DOM來表示真實的DOM結構,當監聽到數據變化時,Vue會生成新的虛擬節點與老的虛擬節點進行比較,然后通過一個diff算法計算出最小的變更步驟來更新真實的DOM。
?
總結來說,Vue通過定義屬性的getter和setter以及重寫數組方法來監聽對象和數組的變化。當數據變化被監聽到后,Vue通過內部的Watcher機制和虛擬DOM技術來確保視圖能夠高效且準確地更新。
在 Vue2 中,響應式原理**基于 Object.defineProperty** 實現,而在 Vue3 中,響應式原理是**通過 Proxy 對象實現的**。
Vue2 的響應式原理利用了 JavaScript 中的 `Object.defineProperty` 方法。此方法允許開發者定義對象屬性的 getter 和 setter,使得當這些屬性被讀取或賦值時,可以執行自定義的操作。Vue2 在初始化過程中會遍歷 data 對象的所有屬性,為每個屬性設置 getter 和 setter,同時收集依賴(即哪些地方使用了這個屬性),并在屬性值改變時通知這些依賴進行更新。
Vue3 則采用了 ES6 的 `Proxy` 對象來實現響應式。`Proxy` 可以代理對象的全部屬性,并且能夠輕松地對新增或刪除的屬性進行處理。與 `Object.defineProperty` 相比,它能夠在更多操作(如數組索引的變更)上提供攔截能力。Vue3 結合了 `Reflect` 來確保 `Proxy` 處理中的一致性和正確性。
兩者的主要區別在于:
1. **監聽方式**:Vue2 使用的是屬性級別的監聽,而 Vue3 實現了對象級別的全局監聽。
2. **新增和刪除屬性**:Vue2 對于對象新增或刪除的屬性無法做出響應式處理,除非使用特定的 API 方法;Vue3 由于使用了 Proxy,能夠自然地處理這種情況。
3. **性能**:在 Vue2 中,由于需要遞歸遍歷所有屬性,在處理具有大量屬性的對象時可能會有性能損耗。而 Vue3 通過 Proxy 避免了這種遞歸過程,提高了性能。