前言
对于jQuery的数据缓存相信大家都不会陌生jQuery缓存系统不仅运用于DOM元素动画事件等都有用到这个缓存系统所以在平时实际应用中 我们经常需要给元素缓存一些数据并且这些数据往往和DOM元素紧密相关由于DOM元素(节点)也是对象 所以我们可以直接扩展DOM元素的属性但是如果给DOM元素添加自定义的属性和过多的数据可能会引起内存洩漏所以应该要尽量避免这样做 因此更好的解决方法是使用一种低耦合的方式让DOM和缓存数据能够联系起来
另外对于jQuerydata和jQueryremoveData静态方法以及基于这两个方法的原型扩展方法的介绍和用法就不多说了可以查看官方API文档
实现思路
jQuery提供了一套灵活和强大的缓存方法
()先在jQuery内部创建一个cache对象{} 来保存缓存数据 然后往需要进行缓存的DOM节点上扩展一个值为expando的属性 这里是”jQuery” + (new Date)getTime() 注expando的值等于”jQuery”+当前时间 元素本身具有这种属性的可能性很少所以可以忽略沖突
()接着把每个节点的dom[expando]的值都设为一个自增的变量id保持全局唯一性 这个id的值就作为cache的key用来关联DOM节点和数据也就是说cache[id]就取到了这个节点上的所有缓存即id就好比是打开一个房间(DOM节点)的钥匙 而每个元素的所有缓存都被放到了一个map映射里面这样可以同时缓存多个数据
()所以cache对象结构应该像下面这样
复制代码 代码如下:
var cache = {
"uuid
": { // DOM节点
缓存数据
"uuid
"相当于dom
[expando]
"name
": value
"name
": value
}
"uuid
": { // DOM节点
缓存数据
“uuid
"相当于dom
[expando]
"name
": value
"name
": value
}
//
};
每个uuid对应一个elem缓存数据每个缓存对象是可以由多个name/value(名值对)对组成的而value是可以是任何数据类型的
简单模拟实现
根据以上思路就可以简单实现下jQuerydata和jQueryremoveDate的功能了
复制代码 代码如下:
(function(window
undefined) {
var cacheData = {}
// 用来存储数据的对象
win = window
// 把window缓存给一个变量
uuid =
// 声明随机数(
位)
// 注意+new Date()生成的随机数是Number类型
与一个空字符串连接后(或使用toString方法转型后)变成字符串
才可使用slice方法
expando = "cacheData" + (+new Date() + "")
slice(
);
// (+new Date())
toString()
slice(
)等价于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 {
// IE
即标准浏览器可以直接使用delete来删除属性
delete elem[expando];
} catch (e) {
// IE
/IE
使用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结构
复制代码 代码如下:
<div id="demo" style="height:
px; width:
px; background: #ccc; color: #fff; margin:
px; text
align: center; line
height:
px;">
demo
</div>
js代码
复制代码 代码如下:
window
onload = function() {
// 测试
var demo = document
getElementById("demo");
// 写入缓存
data(demo
"myName"
"hcy");
console
log(data(demo
"myName")); // hcy
data(demo
"myBlog"
"
console
log(data(demo
"myBlog")); //
// 删除DOM元素的某个缓存值
removeData(demo
"myBlog");
console
log(data(demo
"myBlog")); // undefined
console
log(data(demo
"myName")); // hcy
console
log(demo[expando]); //
// 删除DOM元素
removeData(demo);
console
log(demo[expando]); // undefined
};
firefox下例子结果截图
对于上述例子实现jQuery的简单缓存系统先给该DOM元素添加一个随机生成的属性expando这个属性用来存放访问缓存数据的id值就好比DOM元素都有一把开启缓存保险箱的钥匙只要有了钥匙就可以随时开启缓存保险箱 将本来存放到DOM元素中的数据都转到了缓存中而DOM元素本身只要存储一个简单的属性就可以了这样就可以将由DOM元素引起的内存洩漏(具体会发生什么状况不知道大家都这么说~)的风险规避到最小
结语
糊里糊涂地又到了最后有一些术语或解释上可能存在偏差望各位童鞋指正和给出一些建议另外从理论上讲 data和removeData方法可以用于任何对象的缓存 不过如果运用于本地对象或window对象 会存在内存洩露循环引用等问题(^_^从网上看到的) 所以一般还是用于DOM节点比较适合还可以结合事件动画对DOM节点进行缓存数据的操作pscache真的很重要!需要慢慢体会~
因为分享所以简单因为分享所以快乐