热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

jQuery数据缓存功能的实现思路及简单模拟

jQuery缓存系统不仅运用于DOM元素,动画、事件等都有用到这个缓存系统
前言
对于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方法。
expando = "cacheData" + (+new Date() + "").slice(-8);
// (+new Date()).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
};

firefox下例子结果截图:
 
对于上述例子实现jQuery的简单缓存系统:先给该DOM元素添加一个随机生成的属性expando,这个属性用来存放访问缓存数据的id值,就好比DOM元素都有一把开启缓存保险箱的钥匙,只要有了钥匙就可以随时开启缓存保险箱。 将本来存放到DOM元素中的数据都转到了缓存中,而DOM元素本身只要存储一个简单的属性就可以了,这样就可以将由DOM元素引起的内存泄漏(具体会发生什么状况不知道,大家都这么说~)的风险规避到最小。

结语
糊里糊涂地又到了最后,有一些术语或解释上可能存在偏差,望各位童鞋指正和给出一些建议;另外,从理论上讲, data和removeData方法可以用于任何对象的缓存, 不过如果运用于本地对象或window对象, 会存在内存泄露、循环引用等问题(^_^从网上看到的), 所以一般还是用于DOM节点比较适合,还可以结合事件、动画对DOM节点进行缓存数据的操作。ps:cache真的很重要!需要慢慢体会~
因为分享,所以简单;因为分享,所以快乐。
推荐阅读
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • HTML5网页模板怎么加百度统计?
    本文介绍了如何在HTML5网页模板中加入百度统计,并对模板文件、css样式表、js插件库等内容进行了说明。同时还解答了关于HTML5网页模板的使用方法、表单提交、域名和空间的问题,并介绍了如何使用Visual Studio 2010创建HTML5模板。此外,还提到了使用Jquery编写美好的HTML5前端框架模板的方法,以及制作企业HTML5网站模板和支持HTML5的CMS。 ... [详细]
  • 本文介绍了网页播放视频的三种实现方式,分别是使用html5的video标签、使用flash来播放以及使用object标签。其中,推荐使用html5的video标签来简单播放视频,但有些老的浏览器不支持html5。另外,还可以使用flash来播放视频,需要使用object标签。 ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
  • 本文介绍了Java后台Jsonp处理方法及其应用场景。首先解释了Jsonp是一个非官方的协议,它允许在服务器端通过Script tags返回至客户端,并通过javascript callback的形式实现跨域访问。然后介绍了JSON系统开发方法,它是一种面向数据结构的分析和设计方法,以活动为中心,将一连串的活动顺序组合成一个完整的工作进程。接着给出了一个客户端示例代码,使用了jQuery的ajax方法请求一个Jsonp数据。 ... [详细]
  • jQuery如何判断一个元素是否被点击?
    本文介绍了使用jQuery判断一个元素是否被点击的方法,并通过示例进行了具体说明。注意要指定父级,否则会执行多次。 ... [详细]
  • 本文介绍了如何在Jquery中通过元素的样式值获取元素,并将其赋值给一个变量。提供了5种解决方案供参考。 ... [详细]
  • Apache Shiro 身份验证绕过漏洞 (CVE202011989) 详细解析及防范措施
    本文详细解析了Apache Shiro 身份验证绕过漏洞 (CVE202011989) 的原理和影响,并提供了相应的防范措施。Apache Shiro 是一个强大且易用的Java安全框架,常用于执行身份验证、授权、密码和会话管理。在Apache Shiro 1.5.3之前的版本中,与Spring控制器一起使用时,存在特制请求可能导致身份验证绕过的漏洞。本文还介绍了该漏洞的具体细节,并给出了防范该漏洞的建议措施。 ... [详细]
  • 本文介绍了使用jQuery实现图片预加载和等比例缩放的方法,同时提供了演示和相关代码。该方法可以重置图片的宽度和高度,并使图片在水平和垂直方向上居中显示。 ... [详细]
  • 本文介绍了DataTables插件的官方网站以及其基本特点和使用方法,包括分页处理、数据过滤、数据排序、数据类型检测、列宽度自动适应、CSS定制样式、隐藏列等功能。同时还介绍了其易用性、可扩展性和灵活性,以及国际化和动态创建表格的功能。此外,还提供了参数初始化和延迟加载的示例代码。 ... [详细]
  • 获取ul中第一个li元素的五种方法和多个ul中第一个li元素的四种方法
    本文介绍了获取ul中第一个li元素的五种方法和多个ul中第一个li元素的四种方法,包括使用jQuery的选择器和遍历方法。通过这些方法,可以方便地获取到所需的元素,并进行相应的操作。 ... [详细]
  • 如何压缩网站页面以减少页面加载时间
    本文介绍了影响网站打开时间的两个因素,即网页加载速度和网站页面大小。重点讲解了如何通过压缩网站页面来减少页面加载时间。具体包括图片压缩、Javascript压缩、CSS压缩和HTML压缩等方法,并推荐了相应的压缩工具。此外,还提到了一款Google Chrome插件——网页加载速度分析工具Speed Tracer。 ... [详细]
author-avatar
eea1051113
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有