jQuery 的數據緩存系統最早可追溯至 1.2 版本。當時事件系統直接引用了 Dean Edwards 的 addEvent.js,但該實現將事件回調直接掛載在 EventTarget 上,導致循環引用風險,若目標為 window 更會造成全域汙染。數據緩存系統的引入不僅規避了這兩大隱患,更能有效保存各模組產生的中介變量,解耦模組間依賴。對 jQuery 而言,事件複製乃至後來的隊列機制,無一不建立在緩存系統之上。
data 與 removeDatajQuery 1.2 在 core 模組新增 $.data 與 $.removeData 兩個靜態方法。緩存機制將所有數據存放在 $.cache 物件上,為每個需使用緩存的 DOM 元素、document 或 window 分配一個 UUID。UUID 的屬性名採用 "jQuery" + (new Date()).getTime() 形式,值為從 0 起遞增的整數。為避免 window 物件被汙染,內部判斷若為 window 則映射到一個名為 windowData 的空物件上。首次訪問時,會在 $.cache 中開闢一個空物件(緩存體)存放相關數據,UUID 猶如存摺。removeData 刪除無用數據,若緩存體變為空物件,則從 $.cache 移除並清除目標物件上的 UUID。

新增同名原型方法 data、removeData,支援鏈式調用與集合操作,並在 data 中加入 getData、setData 自定義事件觸發邏輯。
數據緩存獨立為 data.js 模組,新增命名空間與原型上的 queue/dequeue 方法,專為動畫模組服務——queue 緩存一組數據,dequeue 依序取出執行。


元素若帶有自定義屬性(UUID),複製時會一併複製導致 UUID 衝突。早期 jQuery 複製節點若 cloneNode 不複製事件則直接使用,否則用 outerHTML/innerHTML 經 clean 解析重建,並用正則清除顯式屬性。

noData 與多數據存儲針對 IE 下 object、embed、applet 三類標籤無法隨意擴展屬性的問題,引入 noData 哈希表標記不緩存。$.data 支援第二參數為物件以便批量存儲。UUID 對應的 expando 移入命名空間,隊列方法剝離為獨立模組。

changeData 自定義事件,實用性有限。acceptData 方法,發現載入 Flash 的 object 仍可擴展屬性,故放寬限制;檢測邏輯因涉及 classid 判斷而變複雜,獨立出來可復用並節省體積。data-* 屬性:首次訪問元素時遍歷所有 data-* 屬性(兼容舊 IE 不用 dataset)寫入緩存體;讀取時優先緩存,無則回退 getAttribute。並將字串自動轉型:"true"/"false"/"null" 轉布林/空值,數字字串轉數值,{...} 形式嘗試 JSON.parse 轉物件。
expando 改為版本號+隨機數,支援同頁多版本共存。hasData、dataAttr 方法;dataAttr 用 JSON.parse 但需防範 JSON2 汙染 toJSON 導致 for...in 判空失效,故新增 isEmptyDataObject。jQuery.expando 為鍵的子物件存放系統數據(事件數據為兼容仍置頂層)。data 新增第四參數標記系統數據,removeData 第三參數對應刪除,另設 _data 專操作系統數據。
1.8 嘗試 deleteIds 回收 UUID 但很快移除;UUID 生成改用 jQuery.guid。1.8.3 後核心操作抽為私有方法,公開 API 僅作代理,分為用戶數據(data/removeData)與系統數據(_data/_removeData)兩條線,緩存系統成為龐大家族。

總結而言,數據緩存本質是在目標物件與緩存體間建立一對一映射,複雜度集中在映射建立與維護,核心操作只是普通物件屬性增刪改查,完美吻合 KISS 原則與單一職責原則。
原文連結:https://www.cnblogs.com/rubylouvre/archive/2012/11/19/2776286.html