Vue數(shù)據(jù)響應(yīng)式原理步驟解析
Vue 的數(shù)據(jù)響應(yīng)式原理是其核心特性之一,它實現(xiàn)了數(shù)據(jù)變化自動驅(qū)動視圖更新。Vue 2.x 和 Vue 3.x 的實現(xiàn)方式不同,下面分別詳解:
Vue 2.x 的響應(yīng)式原理(基于 Object.defineProperty)
核心步驟:
數(shù)據(jù)劫持(Observer):
-遍歷 data 中的每個屬性,用 Object.defineProperty 重寫其 getter/setter。
-每個屬性關(guān)聯(lián)一個 Dep 實例(依賴收集器)。依賴收集(Dependency Collection):
-當(dāng)組件渲染時,會訪問數(shù)據(jù)屬性,觸發(fā) getter。
-此時 Dep 會記錄當(dāng)前 Watcher(每個組件對應(yīng)一個渲染 Watcher)。派發(fā)更新(Dispatching Updates):
-當(dāng)數(shù)據(jù)被修改時,觸發(fā) setter。
-Dep 通知所有關(guān)聯(lián)的 Watcher 執(zhí)行更新(如重新渲染組件)。數(shù)組的特殊處理:
-重寫數(shù)組的 7 個方法(push/pop/shift/unshift/splice/sort/reverse),在調(diào)用這些方法時手動觸發(fā)更新。
-通過 proto 繼承改寫后的數(shù)組方法(或直接覆蓋原型)。
代碼簡化示例:
class Dep { constructor() { this.subs = new Set(); } depend() { if (currentWatcher) this.subs.add(currentWatcher); } notify() { this.subs.forEach(watcher => watcher.update()); } } function defineReactive(obj, key) { const dep = new Dep(); let value = obj[key]; Object.defineProperty(obj, key, { get() { dep.depend(); // 收集依賴 return value; }, set(newVal) { value = newVal; dep.notify(); // 觸發(fā)更新 } }); }
局限性:
- 無法檢測新增/刪除屬性 → 需用 Vue.set/Vue.delete。
- 數(shù)組索引/長度修改無法監(jiān)聽 → 需用重寫的方法或 Vue.set。
- 遞歸遍歷對象性能損耗。
Vue 3.x 的響應(yīng)式原理(基于 Proxy)
Vue 3 使用 Proxy 替代 Object.defineProperty,徹底解決 Vue 2 的痛點。
核心步驟:
代理對象(Reactive):
-通過 Proxy 包裹目標(biāo)對象,攔截 所有操作(增/刪/改/查/遍歷等)。
-每個對象關(guān)聯(lián)一個 ReactiveEffect 集合。
依賴收集:
-當(dāng)訪問數(shù)據(jù)時,觸發(fā) get 攔截,收集當(dāng)前活躍的 Effect(副作用函數(shù))。
觸發(fā)更新:
-當(dāng)修改數(shù)據(jù)時,觸發(fā) set 或 deleteProperty 攔截,通知所有關(guān)聯(lián)的 Effect 重新執(zhí)行。
代碼簡化示例:
const targetMap = new WeakMap(); // 存儲所有依賴 function track(target, key) { if (!activeEffect) return; let depsMap = targetMap.get(target); if (!depsMap) targetMap.set(target, (depsMap = new Map())); let dep = depsMap.get(key); if (!dep) depsMap.set(key, (dep = new Set())); dep.add(activeEffect); // 收集當(dāng)前 Effect } function trigger(target, key) { const depsMap = targetMap.get(target); if (!depsMap) return; depsMap.get(key)?.forEach(effect => effect.run()); // 執(zhí)行所有 Effect } const proxy = new Proxy(data, { get(target, key) { track(target, key); // 訪問時收集依賴 return Reflect.get(target, key); }, set(target, key, value) { Reflect.set(target, key, value); trigger(target, key); // 修改時觸發(fā)更新 return true; } });
優(yōu)勢:
- 支持監(jiān)聽動態(tài)新增/刪除屬性。
- 支持監(jiān)聽數(shù)組索引和長度變化。
- 惰性收集:僅代理訪問到的屬性,減少初始化開銷。
- 統(tǒng)一處理對象/數(shù)組,無需特殊邏輯。
關(guān)鍵概念補充
副作用函數(shù)(Effect):
-Vue 3 使用 ReactiveEffect 封裝更新邏輯(相當(dāng)于 Vue 2 的 Watcher)。
-組件渲染、計算屬性、偵聽器都是副作用函數(shù)。
響應(yīng)式 API:
-reactive():創(chuàng)建深層次響應(yīng)式對象(基于 Proxy)。
-ref():將基本類型包裝為 { value: … } 的響應(yīng)式引用(通過 .value 訪問)。
-computed/watch:基于 Effect 系統(tǒng)實現(xiàn)。
依賴清理:
-每次執(zhí)行 Effect 前清理舊依賴,避免無效更新(如條件分支變化時)。
總結(jié)對比
特性 | Vue 2(Object.defineProperty) | Vue 3(Proxy) |
---|---|---|
對象監(jiān)聽 | 遞歸遍歷屬性 | 直接代理整個對象 |
新增/刪除屬性 | 不支持(需 Vue.set) | 支持 |
數(shù)組監(jiān)聽 | 需重寫方法 | 直接支持索引修改 |
性能 | 初始化遞歸消耗大 | 按需代理,內(nèi)存更優(yōu) |
兼容性 | 支持 IE9+ | 不支持 IE(需 Polyfill) |
Vue 3 的響應(yīng)式系統(tǒng)獨立為庫 @vue/reactivity,可脫離框架使用。
到此這篇關(guān)于Vue數(shù)據(jù)響應(yīng)式原理解析的文章就介紹到這了,更多相關(guān)Vue數(shù)據(jù)響應(yīng)式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue?中ref()和?reactive()響應(yīng)式數(shù)據(jù)的使用方法
- Vue3.0使用ref和reactive來創(chuàng)建響應(yīng)式數(shù)據(jù)
- Vue3 響應(yīng)式數(shù)據(jù) reactive使用方法
- 詳解vue2和vue3如何定義響應(yīng)式數(shù)據(jù)
- 一文詳解Vue響應(yīng)式數(shù)據(jù)的原理
- Vue3關(guān)于響應(yīng)式數(shù)據(jù)類型詳解(ref、reactive、toRef、及toRefs)
- Vue.js響應(yīng)式數(shù)據(jù)的簡單實現(xiàn)方法(一看就會)
- vue3.x源碼剖析之?dāng)?shù)據(jù)響應(yīng)式的深入講解
- 稍微學(xué)一下Vue的數(shù)據(jù)響應(yīng)式(Vue2及Vue3區(qū)別)
- 使用Vue.set()方法實現(xiàn)響應(yīng)式修改數(shù)組數(shù)據(jù)步驟
- Vue.js中provide/inject實現(xiàn)響應(yīng)式數(shù)據(jù)更新的方法示例
- Vue3.0數(shù)據(jù)響應(yīng)式原理詳解
相關(guān)文章
利用vue + koa2 + mockjs模擬數(shù)據(jù)的方法教程
這篇文章主要給大家介紹了關(guān)于利用vue + koa2 + mockjs模擬數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11Vue2.x如何解決Element組件el-tooltip滾動時錯位不消失的問題
這篇文章主要介紹了Vue2.x如何解決Element組件el-tooltip滾動時錯位不消失的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06Vue this.$router.push(參數(shù))實現(xiàn)頁面跳轉(zhuǎn)操作
這篇文章主要介紹了Vue this.$router.push(參數(shù))實現(xiàn)頁面跳轉(zhuǎn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09Vue子組件向父組件通信與父組件調(diào)用子組件中的方法
這篇文章主要介紹了Vue子組件向父組件通信與父組件調(diào)用子組件中的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-06-06