一、核心區別
1. 數據類型與使用場景
? ref
可定義基本類型(字符串、數字、布爾值)和對象類型的響應式數據。對于對象類型,`ref` 內部會自動調用 `reactive` 將其轉換為響應式對象。 語法特點:需通過 `.value` 訪問或修改數據(模板中自動解包,無需 `.value`)。 適用場景:簡單數據、需跨組件傳遞的獨立變量、需要重新賦值的場景(如替換整個對象)。
? reactive
僅支持對象類型(對象、數組、Map/Set 等),通過 `Proxy` 實現深度響應式代理。 語法特點:直接訪問屬性(如 `state.count`),無需 `.value`,但無法直接替換整個對象(需用 `Object.assign` 合并更新)。 適用場景:復雜嵌套對象、需深度響應式追蹤的復雜數據結構。
2. 響應式機制差異
ref 底層原理
通過封裝對象的 `.value` 屬性實現響應式: ? 對基本類型使用 `Object.defineProperty` 的 `get/set` 進行數據劫持。 ? 對對象類型內部調用 `reactive` 轉換為 `Proxy` 代理。 ```javascript// 簡化的 ref 實現邏輯function ref(value) {return {get value() { track(this, 'value'); return value; },set value(newVal) { value = newVal; trigger(this, 'value'); }};}```
reactive 底層原理
基于 `Proxy` 攔截對象屬性的增刪改查,結合 `Reflect` 操作原始數據: ```javascript// 簡化的 reactive 實現邏輯function reactive(obj) {return new Proxy(obj, {get(target, key) { track(target, key); return Reflect.get(target, key); },set(target, key, value) { Reflect.set(target, key, value); trigger(target, key); return true;}});}```所有嵌套屬性均會被遞歸代理,實現深層響應性。
二、關鍵特性對比
特性 | ref | reactive |
---|---|---|
數據類型 | 基本類型 + 對象類型 | 僅對象類型 |
訪問方式 | 需 .value (模板自動解包) | 直接訪問屬性(如 state.key ) |
重新賦值 | 支持(通過 .value = ) | 需合并更新(如 Object.assign ) |
解構響應性 | 解構后仍需 .value | 解構會丟失響應性,需 toRefs |
性能 | 基本類型更輕量 | 復雜對象更高效(Proxy 深度監聽) |
三、設計理念與使用建議
1. 設計哲學
? ref
提供單一值響應式的原子化封裝,適合組件間傳遞獨立狀態。
? reactive
針對復雜狀態樹設計,通過 Proxy
實現細粒度依賴追蹤,優化深層更新性能。
2. 使用建議
? 優先 ref
的場景:
? 簡單數據(如計數器、表單字段)。 ? 需要頻繁替換整個對象(如接口返回數據更新)。
? 優先 reactive
的場景:
? 復雜配置對象(如含多層嵌套的表單數據)。 ? 需要自動追蹤屬性增刪的場景(如動態表單字段)。
3. 注意事項
? reactive
直接替換整個對象會丟失響應性,需用 Object.assign
合并更新。
? 模板中 ref
對象自動解包,但 JavaScript 中必須使用 .value
。
? 使用 toRefs
解構 reactive
對象可保持響應性。
四、總結
ref
和 reactive
是 Vue3 響應式系統的兩大核心 API:
? ref
通過 .value
封裝簡化基本類型響應式,兼顧對象類型的靈活性。
? reactive
利用 Proxy
實現深度監聽,適合復雜狀態管理。
開發者應根據數據類型、更新頻率及使用場景選擇最合適的 API,必要時結合 toRefs
優化代碼結構。
異步輸出
async await后面的任務是會加入微任務隊列,本身是同步函數的話直接就console.log()
this指向輸出
const定義變量時不會被掛載到window上