Vue響應式系統演進與實現解析

一、Vue 2 響應式實現詳解

1. 核心代碼實現

// 依賴收集器(觀察者模式)
class Dep {constructor() {this.subscribers = new Set();}depend() {if (activeEffect) {this.subscribers.add(activeEffect);}}notify() {this.subscribers.forEach(effect => effect());}
}let activeEffect = null;// 響應式轉換核心
function defineReactive(obj, key, val) {const dep = new Dep();Object.defineProperty(obj, key, {get() {dep.depend(); // 收集依賴return val;},set(newVal) {if (newVal !== val) {val = newVal;dep.notify(); // 觸發更新}}});
}// 遞歸處理對象
function observe(obj) {Object.keys(obj).forEach(key => {let value = obj[key];if (typeof value === 'object' && value !== null) {observe(value); // 遞歸處理嵌套對象}defineReactive(obj, key, value);});
}// 數組方法重寫
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift'].forEach(method => {const original = arrayProto[method];arrayMethods[method] = function(...args) {const result = original.apply(this, args);this.__ob__.dep.notify(); // 手動觸發更新return result;};
});

2. 使用步驟

const data = { count: 0, list: [1,2,3] };
observe(data);// 定義響應式副作用
function watchEffect(fn) {activeEffect = fn;fn();activeEffect = null;
}watchEffect(() => {console.log('Count changed:', data.count);
});data.count = 5; // 觸發日志輸出
data.list.push(4); // 觸發更新

3. 關鍵問題示例

// 動態屬性問題
data.newProp = 'test'; // ? 不會觸發更新
Vue.set(data, 'newProp', 'test'); // ? 正確方式// 數組索引修改問題
data.list[0] = 99; // ? 不會觸發
data.list.splice(0, 1, 99); // ? 正確方式

二、Vue 3 響應式實現詳解

1. 核心代碼實現

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);
}function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;const effects = depsMap.get(key);effects && effects.forEach(effect => effect());
}const reactiveMap = new WeakMap();function reactive(obj) {if (reactiveMap.has(obj)) return reactiveMap.get(obj);const proxy = new Proxy(obj, {get(target, key, receiver) {track(target, key);const res = Reflect.get(target, key, receiver);if (typeof res === 'object' && res !== null) {return reactive(res); // 惰性遞歸代理}return res;},set(target, key, value, receiver) {Reflect.set(target, key, value, receiver);trigger(target, key);return true;},// 處理 delete 操作deleteProperty(target, key) {const hasKey = Object.prototype.hasOwnProperty.call(target, key);const result = Reflect.deleteProperty(target, key);if (hasKey && result) {trigger(target, key);}return result;}});reactiveMap.set(obj, proxy);return proxy;
}// 處理基本類型
function ref(value) {return {get value() {track(this, 'value');return value;},set value(newVal) {value = newVal;trigger(this, 'value');}};
}

2. 使用步驟

const state = reactive({ count: 0, items: ['apple'] });
const num = ref(10);// 響應式副作用
function effect(fn) {activeEffect = fn;fn();activeEffect = null;
}effect(() => {console.log('State changed:', state.count, num.value);
});state.count++; // ? 觸發更新
state.items.push('banana'); // ? 自動觸發
num.value = 20; // ? 觸發更新

三、技術對比全景圖
特性Vue 2 (Object.defineProperty)Vue 3 (Proxy)
動態屬性檢測需手動調用 Vue.set自動檢測
數組處理需重寫 7 個方法原生支持所有操作
性能初始化O(n) 立即遞歸O(1) 惰性代理
嵌套對象處理初始化時完全遞歸按需代理
數據類型支持對象/數組支持 Map/Set/WeakMap 等
兼容性IE9+不支持 IE11 及以下
內存占用每個屬性創建 Dep 實例整個對象共享依賴映射

四、關鍵演進技術點

1. 依賴收集機制升級

  • Vue 2:每個屬性對應一個 Dep 實例
  • Vue 3:通過 WeakMap 建立三級映射關系:
    targetMap: WeakMap<Target, depsMap>
    depsMap: Map<Key, dep>
    dep: Set<Effect>
    

2. 性能優化策略

  • 惰性代理:只有訪問到的屬性才會被代理
  • 緩存機制reactiveMap 避免重復代理同一對象
  • 批量更新:通過調度器合并多次數據變更

3. 新數據結構支持

// 支持 Map 的響應式
const mapState = reactive(new Map());
mapState.set('key', 'value'); // ? 自動觸發更新// 支持 Set 的操作
const setState = reactive(new Set());
setState.add(123); // ? 觸發更新

五、最佳實踐指南

Vue 2 項目注意事項

  1. 動態添加屬性必須使用 Vue.set
  2. 數組操作優先使用變異方法
  3. 復雜數據結構建議提前初始化完整結構

Vue 3 開發技巧

// 解構保持響應式
const state = reactive({ x: 1, y: 2 });
const { x, y } = toRefs(state); // 使用 toRefs// 組合式 API 示例
import { reactive, watchEffect } from 'vue';export default {setup() {const state = reactive({ count: 0 });watchEffect(() => {console.log('Current count:', state.count);});return { state };}
}

六、總結與展望

核心演進價值

  1. 開發體驗:減少心智負擔,代碼更符合直覺
  2. 性能突破:大型應用響應式處理效率提升 2-5 倍
  3. 擴展能力:為未來響應式數據庫等高級特性鋪路

通過深入理解 Vue 響應式系統的演進,開發者不僅能寫出更高效的代碼,更能把握前端框架設計的核心思想。這種從「屬性劫持」到「代理攔截」的轉變,體現了前端技術追求更優雅、更高效的永恒主題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/906335.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906335.shtml
英文地址,請注明出處:http://en.pswp.cn/news/906335.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mujoco 學習系列(一)安裝與部署

這個系列文章用來記錄 Google DeepMind 發布的 Mujoco 仿真平臺的使用過程&#xff0c;Mujoco 是具身智能領域中非常知名的仿真平臺&#xff0c;以簡單易用的API和精準的物理引擎而著稱&#xff08;PS&#xff1a;原來Google能寫好API文檔啊&#xff09;&#xff0c;也是我平時…

Ai學習之openai api

一、什么是openai api 大家對特斯拉的馬斯克應該是不陌生的&#xff0c;openai 就是馬斯克投資的一家研究人工智能的公司&#xff0c;它就致力于推動人工智能技術的發展&#xff0c;目標是確保人工智能對人類有益&#xff0c;并實現安全且通用的人工智能。 此后&#xff0c;O…

leetcode 合并區間 java

用 ArrayList<int[]> merged new ArrayList<>();來定義數組的list將數組進行排序 Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));如果前面的末尾>后面的初始&#xff0c;那么新的currentInterval的末尾這兩個數組末尾的最大值&#xff0c;即…

std::vector<>.emplace_back

emplace_back() 詳解&#xff1a;C 就地構造的效率革命 emplace_back() 是 C11 引入的容器成員函數&#xff0c;用于在容器尾部就地構造&#xff08;而非拷貝或移動&#xff09;元素。這一特性顯著提升了復雜對象的插入效率&#xff0c;尤其適用于構造代價較高的類型。 一、核…

Dify實戰案例《AI面試官》更新,支持語音交互+智能知識庫+隨機題庫+敏感詞過濾等...

大模型應用課又更新了&#xff0c;除了之前已經完結的兩門課&#xff08;視頻圖文&#xff09;&#xff1a; 《Spring AI 從入門到精通》《LangChain4j 從入門到精通》 還有目前正在更新的 《Dify 從入門到實戰》 本周也迎來了一大波內容更新&#xff0c;其中就包括今天要介紹…

AGI大模型(29):LangChain Model模型

1 LangChain支持的模型有三大類 大語言模型(LLM) ,也叫Text Model,這些模型將文本字符串作為輸入,并返回文本字符串作為輸出。聊天模型(Chat Model),主要代表Open AI的ChatGPT系列模型。這些模型通常由語言模型支持,但它們的API更加結構化。具體來說,這些模型將聊天消…

動態IP技術在跨境電商中的創新應用與戰略價值解析

在全球化4.0時代&#xff0c;跨境電商正經歷從"流量紅利"向"技術紅利"的深度轉型。動態IP技術作為網絡基礎設施的關鍵組件&#xff0c;正在重塑跨境貿易的運營邏輯。本文將從技術架構、應用場景、創新實踐三個維度&#xff0c;揭示動態IP如何成為跨境電商突…

android雙屏之副屏待機顯示圖片

摘要&#xff1a;android原生有雙屏的機制&#xff0c;但需要芯片廠商適配框架后在底層實現。本文在基于芯發8766已實現底層適配的基礎上&#xff0c;僅針對上層Launcher部分對系統進行改造&#xff0c;從而實現在開機后副屏顯示一張待機圖片。 副屏布局 由于僅顯示一張圖片&…

STM32之中斷

一、提高程序實時性的架構方案 輪詢式 指的是在程序運行時&#xff0c;首先對所有的硬件進行初始化&#xff0c;然后在主程序中寫一個死循環&#xff0c;需要運行的功能按照順序進行執行&#xff0c;輪詢系統是一種簡單可靠的方式&#xff0c;一般適用于在只需要按照順序執行…

LLM應用開發平臺資料

課程和代碼資料 放下面了&#xff0c;自取&#xff1a; https://pan.quark.cn/s/57a9d22d61e9

硬盤健康檢測與性能測試的實踐指南

在日常使用 Windows 系統的過程中&#xff0c;我們常常需要借助各種工具來優化性能、排查問題或管理文件。針對windows工具箱進行實測解析&#xff0c;發現它整合了多種實用功能&#xff0c;能夠幫助用戶更高效地管理計算機。 以下為測試發現的功能特性&#xff1a; 硬件信息查…

正則表達式進階(三):遞歸模式與條件匹配的藝術

在正則表達式的高級應用中&#xff0c;遞歸模式和條件匹配是處理復雜嵌套結構和動態模式的利器。它們突破了傳統正則表達式的線性匹配局限&#xff0c;能夠應對嵌套括號、HTML標簽、上下文依賴等復雜場景。本文將詳細介紹遞歸模式&#xff08;(?>...)、 (?R) 等&#xff0…

從零開始創建React項目及制作頁面

一、React 介紹 React 是一個由 Meta&#xff08;原Facebook&#xff09; 開發和維護的 開源JavaScript庫&#xff0c;主要用于構建用戶界面&#xff08;User Interface, UI&#xff09;。它是前端開發中最流行的工具之一&#xff0c;廣泛應用于單頁應用程序&#xff08;SPA&a…

【前端部署】通過 Nginx 讓局域網用戶訪問你的純前端應用

在日常前端開發中&#xff0c;我們常常需要快速將本地的應用展示給局域網內的同事或測試人員&#xff0c;而傳統的共享方式往往效率不高。本文將指導你輕松地將你的純前端應用&#xff08;無論是 Vue, React, Angular 或原生項目&#xff09;部署到本地&#xff0c;并配置局域網…

【Python裝飾器深潛】從語法糖到元編程的藝術

目錄 ?? 前言??? 技術背景與價值?? 當前技術痛點??? 解決方案概述?? 目標讀者說明?? 一、技術原理剖析?? 核心概念圖解?? 核心作用講解?? 關鍵技術模塊說明?? 技術選型對比??? 二、實戰演示?? 環境配置要求?? 核心代碼實現案例1:基礎計時裝飾器案…

mbed驅動st7789屏幕-硬件選擇及連接(1)

目錄 1.整體介紹 2. 硬件選擇 2.1 mbed L432KC 2.2 ST7789 240*240 1.3寸 3. mbed與st7789的硬件連接 4. 總結 1.整體介紹 我們在使用單片機做一些項目的時候,交互性是最重要的因素。那么對于使用者而言,交互最直接的體現無非就是視覺感知,那么我們希望將項目通過視覺…

SpringBoot集成Jasypt對數據庫連接密碼進行加密、解密

引入依賴 <!--配置密碼加密--><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.3</version></dependency><plugin><groupId>c…

分類器引導的條件生成模型

分類器引導的條件生成模型 分類器引導的條件生成模型1. **基本概念**2. **核心思想**3. **實現步驟&#xff08;以擴散模型為例&#xff09;**4. **優點**5. **挑戰與注意事項**6. **應用場景**7. **數學推導**總結 分類器引導的條件生成模型 分類器引導的條件生成模型是一種通…

WPF中的ObjectDataProvider:用于數據綁定的數據源之一

ObjectDataProvider是WPF(Windows Presentation Foundation)中一種強大而靈活的數據綁定源&#xff0c;它允許我們將對象實例、方法結果甚至是構造函數的返回值用作數據源。通過本文&#xff0c;我將深入探討ObjectDataProvider的工作原理、使用場景以及如何在實際應用中發揮其…

lasticsearch 報錯 Document contains at least one immense term 的解決方案

一、問題背景 在使用 Elasticsearch 存儲較大字段數據時&#xff0c;出現如下異常&#xff1a; ElasticsearchStatusException: Elasticsearch exception [typeillegal_argument_exception, reasonDocument contains at least one immense term in field"fieldZgbpka"…