標籤:c style class blog code java
前言:jQuery 作為前端使用最多最廣泛的 JS 庫,其源碼每個 JSer 都應該研究一下。早就打算看卻一直被各種事拖著,上次某公司面試時被問到 jQuery 中 data 方法是如何?的,結果答不上來懊悔不已。現在終於下決心開始看 jQuery 的源碼,就從 data 方法開始。本人也是前端新手,如果文章中有理解不當或者錯誤之處,歡迎留言指出,3Q~ jQuery 版本為 1.8.2
data() 的使用方法
// 向一個 dom 元素繫結資料$("#header").data("aaa", 123); // 給 header 綁定了一個資料其key為"aaa",value為123$("#header").data({"name": "xiaoming", "age": 20}); // 也可以將所有資料作為一個對象直接整體綁定在元素上// 擷取繫結資料$("#header").data("aaa"); // 擷取 header 上綁定的 key 為"aaa"的值,如果沒有在 cache 對象(下面分析源碼時會講到)中找到,會解析元素的 html 5 標籤 data-*,並將值存入 cache 對象$("#header").data(); // 擷取 header 上綁定的所有資料// 移除繫結資料$("#header").removeData("name"); // 移除 header 上綁定的 key 為 name 的資料$("#header").removeData(); // 移除 header 上綁定的所有資料
源碼中 data() 方法相關的代碼
jQuery.extend({ // 全域變數,負責儲存給每個 dom 元素繫結的資料 cache: {}, // 全域變數,當已經繫結資料被 cleanData 方法清除以後,回收的 id儲存在改變數中 deletedIds: [], // 目前的版本沒有用到 在(1.9/2.0)版本中將移除 uuid: 0, // 為 jQuery執行個體 添加一個唯一標示,區別不同的 jQuery 執行個體(比如同一工程內不同版本的 jQuery)繫結資料,比如: jQuery164018232414545491338,首碼+版本號碼+隨機數 expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), // 下面幾類元素是不給綁定資料的,如果綁定會報錯 noData: { "embed": true, // 除了 flash 之外的 object 對象 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", "applet": true }, // 判斷一個元素是否已經綁定有資料 hasData: function( elem ) { }, // 綁定資料 ( pvt 為 false 時,資料會添加到 cache 中元素對應 id 下的data 屬性中,pvt 為 true 則把繫結資料直接添加到 cache 中元素對應的id 下,與 data 屬性並列。jQuery 綁定內部資料 events、handle 等都是通過 _data 方法將 pvt 設定為 true ) data: function( elem, name, data, pvt /* 該參數內部使用 */ ) { }, // 移除資料 removeData: function( elem, name, pvt /* 該參數內部使用 */ ) { }, // 僅限內部調用,添加內部資料 _data: function( elem, name, data ) { }, // 判斷一個 dom-節點是否可以綁定資料 acceptData: function( elem ) { }, // 清除節點上綁定的事件和節點的 jQuery 執行個體識別屬性 cleanData: function( elems, /* internal */ acceptData ) { }});jQuery.fn.extend({ // 提供給開發人員調用的綁定資料方法 data: function( key, value ) { }, // 提供給開發人員調用的移除資料方法 removeData: function( key ) { }});// 解析元素中 html5 標籤 data-* 的值。如果在 cache 對象當中已經擷取到對應值則直接返回不解析 data-* 屬性,否則解析 data-* 屬性並且將資料添加至 cache 對象中儲存。function dataAttr( elem, key, data ) { }// 判斷cache 下儲存的資料對象是否為空白,若且唯若資料對象只有一個 data 屬性,且值為空白時才為空白function isEmptyDataObject( obj ) { }
jQuery.extend 與 jQuery.fn.extend 的區別在於:
jQuery.extend 是在 jQuery 這個建構函式上擴充的方法,調用的時候寫成 $.xxx 或者 jQuery.xxx
jQuery.fn.extend 是在 jQuery 原型上擴充的方法,原型上的方法被所有 jQuery 對象共用,調用的時候為 $().xxx
給元素繫結的資料的儲存格式
$("#header").data("title", "hello world");// 執行後列印 $.cache 結果為{ 1: { data: { title : "hello world" } }}// 並且查看 header 元素,發現屬性中多了一行 "jQuery18102873769768048078: 1" 其中 key 值那一長串為 jQuery 執行個體唯一標識,1 是 header 元素繫結的資料在 cache 對象中對應的屬性名稱,該值每次增加 1,$("#footer").data("foot", "goodbye");// 執行後列印 $.cache 結果為{ 1: { data: { title : "hello world" } }, 2: { data: { foot : "goodbye" } }} // 同樣 footer 元素的屬性中多了一行 "jQuery18102873769768048078: 2"
給元素繫結的事件處理常式也會儲存在 cache 對象中
$("#header").click(function(){});// 綁定點擊事件後,$.cache 的內容為 { 1: { data : { title : "hello world" }, events : { click : [] // click 對應的數組內容省略 }, handle : function(){ } // function 的內容及屬性省略 } 2: { data : { foot : "goodbye" } }}// 可見給 dom 元素繫結事件處理常式後,多了 events 和 handle 兩個屬性,jQuery 自動將這些資料繫結到 cache 對象中元素對應的資料對象中
通過全域對象 cache 來儲存 dom 元素上繫結資料,可以避免 dom 對象和 js 對象之間互相引用導致的循環參考問題。