前言 對於jQuery的資料緩存,相信大家都不會陌生,jQuery快取系統不只運用於DOM元素,動畫、事件等都有用到這個快取系統。所以在平時實際應用中, 我們經常需要給元素緩存一些數據,並且這些數據往往和DOM元素緊密相關。由於DOM元素(節點)也是物件, 所以我們可以直接擴展DOM元素的屬性,但是如果給DOM元素添加自訂的屬性和過多的資料可能會引起記憶體洩漏,所以應該要盡量避免這樣做。 因此更好的解決方法是使用一種低耦合的方式讓DOM和快取資料能夠連結起來。
另外:對於jQuery.data和jQuery.removeData靜態方法、以及基於這兩個方法的原型擴展方法的介紹和用法就不多說了,可以查看官方API文檔。
實作想法 jQuery提供了一套靈活且強大的快取方法:
(1)先在jQuery內部建立一個cache物件{}, 來保存快取資料。 然後往需要進行快取的DOM節點上擴展一個值為expando的屬性, 這裡是”jQuery” (new Date).getTime()。 註:expando的值等於”jQuery” 目前時間, 元素本身俱有這種屬性的可能性很少,所以可以忽略衝突。
(2)接著把每個節點的dom[expando]的值都設為一個自增的變數id,保持全域唯一性。 這個id的值就當作cache的key用來關聯DOM節點和資料。也就是說cache[id]就取到了這個節點上的所有緩存,即id就好比是打開一個房間(DOM節點)的鑰匙。 而每個元素的所有快取都被放到了一個map映射裡面,這樣可以同時快取多個資料。
(3)所以cache對象結構應該像下面這樣:
var cache = {
"uuid1": { // DOM節點1快取數據,"uuid1"相當於dom1[expando]
"name1": value1,
"name2": value2
},
"uuid2": { // DOM節點2快取數據,「uuid2"相當於dom2[expando]
"name1": value1,
"name2": value2
}
// ......
};
每個uuid對應一個elem快取數據,每個快取物件是可以由多個name/value(名值對)對組成的,而value是可以是任何資料類型的。
簡單模擬實作 根據以上思路,就可以簡單實作下jQuery.data與jQuery.removeDate的功能了:
(function(window, undefined) {
var cacheData = {}, // 用來儲存資料的物件
win = window, // 把window快取給一個變數uuid = 0,
// 宣告隨機數(8位元)
// 注意new Date()產生的隨機數是Number類型,與一個空字串連接後(或使用toString方法轉型後)變成字串,才可使用slice方法。 -8)等價於expando
// 寫入快取
var data = function(elem, name, value) {
// 或使用原生方法驗證字串Object.prototype.toString.call( elem) === "[object String]"
// 如果elem為字串
if (typeof elem === "string") {
// 如果傳入name參數,則為寫入入快取
if (name !== undefined) {
cacheData[elem] = name;
}
// 回傳快取資料
return cacheData[elem];
///如果elem為DOM節點
} else if (typeof elem === "object") {
var id,
thisCache;
//elem不存在expando屬性,則加入一個expando屬性(第一次給元素設定快取),否則直接取得現有的expando和id值
if (!elem[expando]) {
id = elem[expando] = uuid;
thisCache = cacheData [id] = {};
} else {
id = elem[expando];
thisCache = cacheData[id];
}
// 把一個隨機數當作目前快取物件的一個屬性,利用該隨機數就能找到該快取物件
if (!thisCache[expando]) {
thisCache[expando] = {};
}
if (value !== undefined) {
// 將資料存到快取物件
thisCache[expando][name] = value;
}
// 傳回DOM元素儲存的資料
return thisCache[expando ][name];
}
};
// 刪除快取
var removeData = function(elem, name) {
// 如果elem為字串,則直接刪除該屬性值
if (typeof elem === "string") {
delete cacheData[elem];
// 如果key為DOM節點
} else if (typeof elem === "object" ) {
// 如果elem不存在expando屬性,則終止執行,不用刪除快取
if (!elem[expando]) {
return;
}
// 偵測物件是否為空
var isEmptyObject = function(obj) {
var name;
for (name in obj) {
return false;
}
return true
}
}
}; 🎜>removeAttr = function() {
try {
// IE8即標準瀏覽器可以直接使用delete來刪除屬性
delete elem[expando];
} catch (e) {
// IE6/IE7使用removeAttribute方法來刪除屬性
elem.removeAttribute(expando);
}
},
id = elem[expando];
if (name) {
// 只刪除指定的資料
delete cacheData[id][expando][name];
// 如果是空對象,id所對應的資料物件全部刪除
if (isEmptyObject(cacheData [id][expando])) {
delete cacheData[id];
removeAttr();
}
} else {
// 刪除DOM元素儲存到快取中的所有資料
delete cacheData[id];
removeAttr();
}
}
};
// 把data和removeData掛在window全域物件下,這樣在外部也能訪問這兩個函數
win.expando = expando;
win.data = data;
win.removeData = removeData;
})(window, undefined);
範例:
HTML結構:
demo
js程式碼:
複製程式碼
程式碼如下
window.onload = function() {
// 測試
var demo = document.getElementById("demo"); // 寫入快取data(demo, "myName", "hcy"); console.log(data(demo, "myName")); // hcy data(demo, "myBlog", "http://www.cnblogs.com /cyStyle"); console.log(data(demo, "myBlog")); // http://www.cnblogs.com/cyStyle // 移除DOM元素的某個快取值removeData(demo, "myBlog"); console.log(data(demo, "myBlog")); // undefined console.log(data(demo, "myName")); // hcy console.log(demo[expando]); // 1 // 刪除DOM元素removeData(demo); console.log(demo[expando]); // undefined console.log(demo[expando]); // undefined };
Firefox での結果の例のスクリーンショット: 上記の例では、jQuery の単純なキャッシュ システムを実装します。まず、ランダムに生成された属性 Expando を DOM 要素に追加します。属性は、キャッシュされたデータにアクセスするための ID 値を保存するために使用されます。これは、DOM 要素にキャッシュ セーフを開くためのキーがあるのと同じで、キーを持っている限り、いつでもキャッシュ セーフを開くことができます。 元々DOM要素に格納されていたデータがキャッシュに転送され、DOM要素自体は単純な属性を格納するだけで済むため、DOM要素によるメモリリークを回避できます(具体的にどうなるかは分かりませんが、誰もが知っているので〜)リスクは最小限に抑えられます。
結論 最後に、いくつかの用語や説明に逸脱があるかもしれません。また、理論的に言えば、いくつかのアドバイスをいただければ幸いです。 、 data メソッドとremoveDataメソッドは、任意のオブジェクトのキャッシュに使用できますが、ローカル オブジェクトやウィンドウ オブジェクトに使用すると、メモリ リークや循環参照などの問題が発生するため (インターネットから見ると ^_^)、通常は DOM ノードに使用されます。さらに適切なのは、イベントとアニメーションを組み合わせて DOM ノードにデータをキャッシュすることもできます。 ps: キャッシュは本当に重要です。ゆっくりとそれを理解する必要があります〜
共有するから、それは簡単です、共有するから、それは幸せです。