Vue數(shù)據(jù)響應(yīng)式原理步驟解析
Vue 的數(shù)據(jù)響應(yīng)式原理是其核心特性之一,它實(shí)現(xiàn)了數(shù)據(jù)變化自動(dòng)驅(qū)動(dòng)視圖更新。Vue 2.x 和 Vue 3.x 的實(shí)現(xiàn)方式不同,下面分別詳解:
Vue 2.x 的響應(yīng)式原理(基于 Object.defineProperty)
核心步驟:
數(shù)據(jù)劫持(Observer):
-遍歷 data 中的每個(gè)屬性,用 Object.defineProperty 重寫(xiě)其 getter/setter。
-每個(gè)屬性關(guān)聯(lián)一個(gè) Dep 實(shí)例(依賴(lài)收集器)。依賴(lài)收集(Dependency Collection):
-當(dāng)組件渲染時(shí),會(huì)訪問(wèn)數(shù)據(jù)屬性,觸發(fā) getter。
-此時(shí) Dep 會(huì)記錄當(dāng)前 Watcher(每個(gè)組件對(duì)應(yīng)一個(gè)渲染 Watcher)。派發(fā)更新(Dispatching Updates):
-當(dāng)數(shù)據(jù)被修改時(shí),觸發(fā) setter。
-Dep 通知所有關(guān)聯(lián)的 Watcher 執(zhí)行更新(如重新渲染組件)。數(shù)組的特殊處理:
-重寫(xiě)數(shù)組的 7 個(gè)方法(push/pop/shift/unshift/splice/sort/reverse),在調(diào)用這些方法時(shí)手動(dòng)觸發(fā)更新。
-通過(guò) proto 繼承改寫(xiě)后的數(shù)組方法(或直接覆蓋原型)。
代碼簡(jiǎn)化示例:
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(); // 收集依賴(lài)
return value;
},
set(newVal) {
value = newVal;
dep.notify(); // 觸發(fā)更新
}
});
}局限性:
- 無(wú)法檢測(cè)新增/刪除屬性 → 需用 Vue.set/Vue.delete。
- 數(shù)組索引/長(zhǎng)度修改無(wú)法監(jiān)聽(tīng) → 需用重寫(xiě)的方法或 Vue.set。
- 遞歸遍歷對(duì)象性能損耗。
Vue 3.x 的響應(yīng)式原理(基于 Proxy)
Vue 3 使用 Proxy 替代 Object.defineProperty,徹底解決 Vue 2 的痛點(diǎn)。
核心步驟:
代理對(duì)象(Reactive):
-通過(guò) Proxy 包裹目標(biāo)對(duì)象,攔截 所有操作(增/刪/改/查/遍歷等)。
-每個(gè)對(duì)象關(guān)聯(lián)一個(gè) ReactiveEffect 集合。
依賴(lài)收集:
-當(dāng)訪問(wèn)數(shù)據(jù)時(shí),觸發(fā) get 攔截,收集當(dāng)前活躍的 Effect(副作用函數(shù))。
觸發(fā)更新:
-當(dāng)修改數(shù)據(jù)時(shí),觸發(fā) set 或 deleteProperty 攔截,通知所有關(guān)聯(lián)的 Effect 重新執(zhí)行。
代碼簡(jiǎn)化示例:
const targetMap = new WeakMap(); // 存儲(chǔ)所有依賴(lài)
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); // 訪問(wèn)時(shí)收集依賴(lài)
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
trigger(target, key); // 修改時(shí)觸發(fā)更新
return true;
}
});優(yōu)勢(shì):
- 支持監(jiān)聽(tīng)動(dòng)態(tài)新增/刪除屬性。
- 支持監(jiān)聽(tīng)數(shù)組索引和長(zhǎng)度變化。
- 惰性收集:僅代理訪問(wèn)到的屬性,減少初始化開(kāi)銷(xiāo)。
- 統(tǒng)一處理對(duì)象/數(shù)組,無(wú)需特殊邏輯。
關(guān)鍵概念補(bǔ)充
副作用函數(shù)(Effect):
-Vue 3 使用 ReactiveEffect 封裝更新邏輯(相當(dāng)于 Vue 2 的 Watcher)。
-組件渲染、計(jì)算屬性、偵聽(tīng)器都是副作用函數(shù)。
響應(yīng)式 API:
-reactive():創(chuàng)建深層次響應(yīng)式對(duì)象(基于 Proxy)。
-ref():將基本類(lèi)型包裝為 { value: … } 的響應(yīng)式引用(通過(guò) .value 訪問(wèn))。
-computed/watch:基于 Effect 系統(tǒng)實(shí)現(xiàn)。
依賴(lài)清理:
-每次執(zhí)行 Effect 前清理舊依賴(lài),避免無(wú)效更新(如條件分支變化時(shí))。
總結(jié)對(duì)比
| 特性 | Vue 2(Object.defineProperty) | Vue 3(Proxy) |
|---|---|---|
| 對(duì)象監(jiān)聽(tīng) | 遞歸遍歷屬性 | 直接代理整個(gè)對(duì)象 |
| 新增/刪除屬性 | 不支持(需 Vue.set) | 支持 |
| 數(shù)組監(jiān)聽(tīng) | 需重寫(xiě)方法 | 直接支持索引修改 |
| 性能 | 初始化遞歸消耗大 | 按需代理,內(nèi)存更優(yōu) |
| 兼容性 | 支持 IE9+ | 不支持 IE(需 Polyfill) |
Vue 3 的響應(yīng)式系統(tǒng)獨(dú)立為庫(kù) @vue/reactivity,可脫離框架使用。
到此這篇關(guān)于Vue數(shù)據(jù)響應(yīng)式原理解析的文章就介紹到這了,更多相關(guān)Vue數(shù)據(jù)響應(yīng)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue?中ref()和?reactive()響應(yīng)式數(shù)據(jù)的使用方法
- Vue3.0使用ref和reactive來(lái)創(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ù)類(lèi)型詳解(ref、reactive、toRef、及toRefs)
- Vue.js響應(yīng)式數(shù)據(jù)的簡(jiǎn)單實(shí)現(xiàn)方法(一看就會(huì))
- vue3.x源碼剖析之?dāng)?shù)據(jù)響應(yīng)式的深入講解
- 稍微學(xué)一下Vue的數(shù)據(jù)響應(yīng)式(Vue2及Vue3區(qū)別)
- 使用Vue.set()方法實(shí)現(xiàn)響應(yīng)式修改數(shù)組數(shù)據(jù)步驟
- Vue.js中provide/inject實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)更新的方法示例
- Vue3.0數(shù)據(jù)響應(yīng)式原理詳解
相關(guān)文章
解決Vue項(xiàng)目打包后打開(kāi)index.html頁(yè)面顯示空白以及圖片路徑錯(cuò)誤的問(wèn)題
這篇文章主要介紹了解決Vue項(xiàng)目打包后打開(kāi)index.html頁(yè)面顯示空白以及圖片路徑錯(cuò)誤的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
vue微信分享出來(lái)的鏈接點(diǎn)開(kāi)是首頁(yè)問(wèn)題的解決方法
這篇文章主要為大家詳細(xì)介紹了vue微信分享出來(lái)的鏈接點(diǎn)開(kāi)是首頁(yè)問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Vue2使用vue-video-player實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能
斷點(diǎn)續(xù)傳是指在文件傳輸過(guò)程中,如果傳輸被中斷或者發(fā)生錯(cuò)誤,可以從上一次中斷的地方繼續(xù)傳輸,而不是從頭開(kāi)始,這對(duì)于大文件的傳輸尤為重要,本文給大家介紹了Vue2使用vue-video-player實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能,需要的朋友可以參考下2025-07-07
vue created鉤子函數(shù)與mounted鉤子函數(shù)的用法區(qū)別
這篇文章主要介紹了vue created鉤子函數(shù)與mounted鉤子函數(shù)的用法區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
vue+elementUI(el-upload)圖片壓縮,默認(rèn)同比例壓縮操作
這篇文章主要介紹了vue+elementUI(el-upload)圖片壓縮,默認(rèn)同比例壓縮操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
Vue表單提交點(diǎn)擊事件只允許點(diǎn)擊一次的實(shí)例
這篇文章主要介紹了Vue表單提交點(diǎn)擊事件只允許點(diǎn)擊一次的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10

