Vue3源碼reactivity響應式篇之Reactive

概覽

vue3中reactive用于將普通對象轉換為響應式對象,它的實現原理是通過ProxyReflect來實現的。具體的實現文件參見packages\reactivity\src\reactive.ts。本文會介紹reactive的相關api如下:

  • reactive:將普通對象轉換為響應式對象
  • readonly:將普通對象轉換為只讀響應式對象
  • isReactive:判斷一個對象是否是響應式對象
  • isReadonly:判斷一個對象是否是只讀響應式對象
  • isShallow:判斷一個對象是否是淺層響應式對象
  • isProxy:判斷一個對象是否是代理對象
  • shallowReactive:創建一個淺層響應式對象
  • shallowReadonly:創建一個淺層只讀響應式對象
  • markRaw:標記一個對象為原始對象,避免被轉換為響應式對象
  • toReadonly:將一個響應式對象轉換為只讀響應式對象

源碼分析

在分析reactive.ts的源碼之前,先了解如下幾個變量,它們分別是:

const reactiveMap = /* @__PURE__ */ new WeakMap(); // 響應式對象的緩存Map
const shallowReactiveMap = /* @__PURE__ */ new WeakMap(); // 淺層響應式對象的緩存Map
const readonlyMap = /* @__PURE__ */ new WeakMap(); // 只讀響應式對象的緩存Map
const shallowReadonlyMap = /* @__PURE__ */ new WeakMap(); // 淺層只讀響應式對象的緩存Map

isReadonly

isReadonly用于判斷一個對象是否是只讀響應式對象,它的實現如下:

function isReadonly(value) {return !!(value && value["__v_isReadonly"]);
}

isReadonly就是判斷參數value__v_isReadonly屬性值的布爾值,若為true則表示是只讀對象;否則不是只讀對象。

reactive

reactive的實現如下:

function reactive(target) {// 判斷target是否是只讀對象,若是,則直接返回if (isReadonly(target)) {return target;}// 調用 createReactiveObject 函數創建響應式對象,并返回return createReactiveObject(target, // 目標對象false, // 是否只讀,默認為falsemutableHandlers, // 普通對象的代理處理函數mutableCollectionHandlers, // 集合對象的代理處理函數reactiveMap // 響應式對象的緩存Map);
}
createReactiveObject

reactive的核心實現是createReactiveObject函數,它的實現如下:

function createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {// 判斷target是否是對象,若不是,則彈出警告,并直接返回if (!isObject(target)) {{warn(`value cannot be made ${isReadonly2 ? "readonly" : "reactive"}: ${String(target)}`);}return target;}if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) {return target;}const targetType = getTargetType(target);if (targetType === 0 /* INVALID */) {return target;}const existingProxy = proxyMap.get(target);if (existingProxy) {return existingProxy;}const proxy = new Proxy(target,targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers);proxyMap.set(target, proxy);return proxy;
}function targetTypeMap(rawType) {switch (rawType) {case "Object":case "Array":return 1 /* COMMON */;case "Map":case "Set":case "WeakMap":case "WeakSet":return 2 /* COLLECTION */;default:return 0 /* INVALID */;}
}
function getTargetType(value) {return value["__v_skip"] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value));
}

createReactiveObject函數接受5個參數,依次為:目標對象target、是否只讀isReadonly2、基本類型處理函數baseHandlers、集合對象的代理處理函數collectionHandlers、響應式對象的緩存proxyMap

createReactiveObject在確保target為對象后,會檢測target是一個響應式對象,若是則直接返回;然后會從緩存proxyMap中獲取target的代理對象,若存在則直接返回該代理對象;否則調用getTargetType函數判斷目標對象target的類型,若類型為INVALID,則直接返回target;否則根據類型創建代理對象,并將其緩存到proxyMap中,最后返回該代理對象。

getTargetType的實現也在上面,若target存在__v_skip屬性且為true,或者target不是可擴展的對象,則返回INVALID;否則根據target的類型調用targetTypeMap函數返回類型。

由上targetTypeMap函數可知,targetTypeMap函數根據target的類型返回一個數字,分別表示:

  • 0INVALID,表示target不是一個對象
  • 1COMMON,表示target是一個普通對象或數組
  • 2COLLECTION,表示target是一個集合對象

綜上,可以理解createReactiveObject函數根據target創建代理對象的邏輯如下:

  • target為普通對象或數組,則創建普通對象的代理對象,使用baseHandlers處理函數;
  • targetMap/Set/WeakMap/WeakSet,則創建集合對象的代理對象,使用collectionHandlers處理函數;
  • 其余情況,則直接返回target

關于處理器baseHandlerscollectionHandlers的實現,會在后面的章節中介紹。

readonly/shallowReactive/shallowReadonly

readonly/shallowReactive/shallowReadonly的實現如下:

function readonly(target) {return createReactiveObject(target,true, // 表示只讀readonlyHandlers, // 普通對象的只讀代理處理函數readonlyCollectionHandlers, // 集合對象的只讀代理處理函數readonlyMap // 只讀響應式對象的緩存readonlyMap);
}function shallowReactive(target) {return createReactiveObject(target,false, // 不是只讀shallowReactiveHandlers, // 普通對象的淺層響應式代理處理函數shallowCollectionHandlers, // 集合對象的淺層響應式代理處理函數shallowReactiveMap // 淺層響應式對象的緩存shallowReactiveMap);
}function shallowReadonly(target) {return createReactiveObject(target,true, // 表示只讀shallowReadonlyHandlers, // 普通對象的淺層只讀代理處理函數shallowReadonlyCollectionHandlers, // 集合對象的淺層只讀代理處理函數shallowReadonlyMap // 淺層只讀響應式對象的緩存shallowReadonlyMap);
}

readonly的實現和reactive的實現類似,不同就是調用createReactiveObject函數時,傳參不同。

類似的還有shallowReactiveshallowReadonly

它們的不同如下所示

函數只讀淺層緩存普通對象的代理方法集合對象的代理方法
reactivereactiveMapbaseHandlerscollectionHandlers
shallowReactiveshallowReactiveMapshallowReactiveHandlersshallowCollectionHandlers
readonlyreadonlyMapreadonlyHandlersreadonlyCollectionHandlers
shallowReadonlyshallowReadonlyMapshallowReadonlyHandlersshallowReadonlyCollectionHandlers

isReactive

isReactive的實現如下:

function isReactive(value) {if (isReadonly(value)) {return isReactive(value["__v_raw"]);}return !!(value && value["__v_isReactive"]);
}

isReactive會先判斷value是否為只讀響應式數據,若為只讀響應式數據,則會遞歸調用isReactive函數判斷value的原始數據是否為響應式數據;否則,會判斷value是否為響應式數據,若為響應式數據,則返回true,否則返回false

isShallow / isProxy / isReadonly

function isShallow(value) {return !!(value && value["__v_isShallow"]);
}
function isProxy(value) {return value ? !!value["__v_raw"] : false;
}
function isReadonly(value) {return !!(value && value["__v_isReadonly"]);
}

isShallow/isProxy/isReadonly的實現都比較簡單,都是判斷參數是否存在某個屬性,若存在則返回true,否則返回false。它們讀取的屬性__v_isShallow/__v_raw/__v_isReadonly實際上都是針對代理對象的,而它們的邏輯處理也是在處理器方法中實現的,后續會講到

markRaw

markRaw用于標記對象為原始對象,這種對象不會被轉換為響應式對象,也不會被代理,其實現如下:

function markRaw(value) {if (!hasOwn(value, "__v_skip") && Object.isExtensible(value)) {def(value, "__v_skip", true);}return value;
}

markRaw首先會判斷對象是否可擴展,若可擴展,則會在對象上定義一個__v_skip屬性,打一個標記,值為true;最后返回該對象。使用reactive(target)創建響應式對象時,若target不可擴展,則在調用createReactiveObject時,其內部調用getTargetType的返回值就是0.

def內部就是調用Object.defineProperty定義對象上屬性

toReadonly

toReadonly用于將響應式對象轉換為只讀對象,其實現如下:

const toReadonly = (value) => isObject(value) ? readonly(value) : value;

toReadonly會判斷參數是否為對象,若為是,則會調用readonly函數將參數轉換為只讀響應式對象,并返回該代理對象;否則,直接返回參數。這和toReactive很類似,只是toReactive會將參數轉換為響應式對象,而toReadonly會將參數轉換為只讀響應式對象。

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

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

相關文章

初識數據結構——Map和Set:哈希表與二叉搜索樹的魔法對決

數據結構專欄 ?(click) 大家好!我是你們的老朋友——想不明白的過度思考者!今天我們要一起探索Java中兩個神奇的數據結構:Map和Set!準備好了嗎?讓我們開始這場魔法之旅吧!🎩 🎯 先…

Unreal Engine UStaticMeshComponent

UnrealUnreal Engine - UStaticMeshComponent🏛 定義🏛 類繼承? 關鍵特性?? 常見配置🛠? 使用方法📚 在 C 中使用📚 在藍圖中使用🎮 典型應用場景📚 常見子類與用途📝 小結Unrea…

demo 汽車之家(渲染-篩選-排序-模塊抽離數據)

效果圖展示:代碼截圖注釋詳情實現筆記總體目標(按需求點對照代碼)數據模塊化、整體渲染框架、篩選/排序的高亮與行為,全部已在 Index.ets CarData.ets 落地。下面按圖片需求 2~4 點逐條總結,并給出關鍵代碼定位與“為…

雙重機器學習DML介紹

本文參考: [1]文心一言回答; 一、核心原理與數學框架 雙重機器學習(Double Machine Learning, DML)由Chernozhukov等學者于2018年提出,是一種結合機器學習與傳統計量經濟學的因果推斷框架。其核心目標是在高維數據和非…

【圖像算法 - 21】慧眼識蟲:基于深度學習與OpenCV的農田害蟲智能識別系統

摘要: 在現代農業生產中,病蟲害是影響作物產量和品質的關鍵因素之一。傳統的害蟲識別依賴人工巡查,效率低、成本高且易出錯。本文將介紹如何利用深度學習與OpenCV構建一套高效的農田害蟲智能識別系統。該系統能夠自動識別10類常見農業害蟲&a…

循環神經網絡實戰:GRU 對比 LSTM 的中文情感分析(三)

循環神經網絡實戰:GRU 對比 LSTM 的中文情感分析(三) 文章目錄循環神經網絡實戰:GRU 對比 LSTM 的中文情感分析(三)前言數據準備(與 LSTM 相同)模型搭建(GRU)…

學習游戲制作記錄(制作提示框以及使用鍵盤切換UI)8.21

1.制作裝備提示框創建提示框,添加文本子對象,用來描述名稱,類型以及屬性加成掛載垂直分配組件和文本大小適配組件,這樣圖像會根據文本大小來調整自己創建UI_ItemTip腳本并掛載在文本框上:[SerializeField] private Tex…

chapter07_初始化和銷毀方法

一、簡介 一個Bean,在進行實例化之后,需要進行兩種初始化 初始化屬性,由PropertyValues進行賦值初始化方法,由ApplicationContext統一調用,例如加載配置文件 Bean的初始化與銷毀,共有三種方式(注…

open webui源碼分析6-Function

一、Functions簡介 可以把Tools作為依賴于外部服務的插件,Functions就是內部插件,二者都是用來增強open webui的能力的。Functions是輕量的,高度可定制的,并且是用純Python編寫的,所以你可以自由地創建任何東西——從新…

C2039 “unref“:不是“osgEarth::Symbology::Style”的成員 問題分析及解決方法

在osgEarth2.10中實現多線段連續測量功能時,遇到下圖中的錯誤; 經過測試和驗證,主要問題出現在下圖圈出代碼的定義上 圖22-1 對于22-1中的兩個變量這樣定義是錯誤的。因為Style類沒有繼承自osg::Referenced,因此不能與osg::ref_ptr配合使用

GitHub 熱榜項目 - 日榜(2025-08-19)

GitHub 熱榜項目 - 日榜(2025-08-19) 生成于:2025-08-19 統計摘要 共發現熱門項目:12 個 榜單類型:日榜 本期熱點趨勢總結 本期GitHub熱榜呈現三大技術熱點:1)AI原生開發持續爆發,Archon OS、Parlant等…

ingress 配置ssl證書

模擬環境舉例&#xff1a; # 生成帶 OU 的證書配置文件 cat > csr.conf <<EOF [ req ] default_bits 2048 prompt no default_md sha256 distinguished_name dn[ dn ] C CN ST Beijing L Beijing O YourCompany, Inc. # 組織名稱 (必填) OU DevOps De…

Pandas 合并數據集:concat 和 append

文章目錄Pandas 合并數據集&#xff1a;concat 和 append回顧&#xff1a;NumPy 數組的拼接使用 pd.concat 進行簡單拼接重復索引將重復索引視為錯誤忽略索引添加多級索引&#xff08;MultiIndex&#xff09;鍵使用連接&#xff08;Join&#xff09;方式拼接append 方法Pandas …

2025年5月架構設計師綜合知識真題回顧,附參考答案、解析及所涉知識點(七)

本文主要回顧2025年上半年(2025-5-24)系統架構設計師考試上午綜合知識科目的選擇題,同時附帶參考答案、解析和所涉知識點。 2025年5月架構設計師綜合知識真題回顧,附參考答案、解析及所涉知識點(一) 2025年5月架構設計師綜合知識真題回顧,附參考答案、解析及所涉知識點(…

面向RF設計人員的微帶貼片天線計算器

微帶貼片天線和陣列可能是僅次于單極天線和偶極天線的最簡單的天線設計。這些天線也很容易集成到PCB中&#xff0c;因此通常用于5G天線陣列和雷達等高級系統。這些天線陣列在基諧模式和高階模式下也遵循一組簡單的設計方程&#xff0c;因此您甚至可以在不使用仿真工具的情況下設…

明基RD280U編程顯示器深度測評:碼農的「第二塊鍵盤」竟然會發光?

文章目錄前言一、開箱篇&#xff1a;當理工男遇到「俄羅斯套娃式包裝」二、外觀篇&#xff1a;深空灰的「代碼容器」1. 桌面變形記2. 保護肩頸的人體工學設計三、顯示篇&#xff1a;給代碼做「光子嫩膚」1. 28寸超大大屏 3:2屏比 4K超清2.專業編程模式&#xff0c;讓代碼一目…

算法114. 二叉樹展開為鏈表

題目&#xff1a;給你二叉樹的根結點 root &#xff0c;請你將它展開為一個單鏈表&#xff1a; 展開后的單鏈表應該同樣使用 TreeNode &#xff0c;其中 right 子指針指向鏈表中下一個結點&#xff0c;而左子指針始終為 null 。 展開后的單鏈表應該與二叉樹 先序遍歷 順序相同。…

智慧能源管理系統:點亮山東零碳園區的綠色引擎

一、概述在全球積極踐行“雙碳”目標的時代浪潮下&#xff0c;山東作為經濟大省&#xff0c;正全力推動產業的綠色變革&#xff0c;零碳園區建設成為其中的關鍵一環。《山東省零碳園區建設方案》明確規劃&#xff0c;到2027年建成15個左右省級零碳園區 &#xff0c;到2030年進一…

分布式日志分析平臺(ELFK 與 EFK)理論

一、日志分析平臺核心概念在分布式系統中&#xff0c;日志是系統運行狀態監控、問題排查和業務分析的重要依據。隨著系統規模擴大&#xff0c;單機日志管理方式已無法滿足需求&#xff0c;分布式日志分析平臺應運而生。其核心目標是實現日志的集中收集、統一處理、高效存儲和可…

CoreShop微信小程序商城框架開啟多租戶-添加一個WPF客戶端以便進行本地操作--讀取店鋪信息(6)

本節內容&#xff0c;使用登錄的token進行店鋪信息讀取&#xff0c;順利的話&#xff0c;進行EXCEL上傳測試。 1。在后臺編寫 讀取店鋪信息代碼 1.1 查看原來鋪店信息在什么位置&#xff0c;店鋪的表格為CoreCmsStore#region 獲取列表// POST: Api/CoreCmsStore/GetPageList///…