jQuery对象数据缓存Cache原理及jQuery.data详解

网上有很多教你怎么使用jQuery.data(..)来实现数据缓存,但有两个用户经常使用的data([key],[value])和jQuery.data(element,[key],[value])几乎没有什么文章说清楚它们两的区别,所以我用到了,研究下分享给大家。
$("").data([key],[value])与jQuery.data(element,[key],[value])的区别
这两个函数都是用来在元素上存放数据也就平时所说的数据缓存,都返回jQuery对象,当时我分别在使用它俩的时候真的吓我一跳,区别可大了,真是不用不知道,一用吓一跳。看例子先吧,后再根据源代码分析。

Js代码  

  1. <div id="test2" onclick="test()">test2</div>
  2. <div id="abc3" onclick="test()">test3</div>
  3. <div id="test" onclick="test()">test</div>
  4. <p id="ttt">aaaa</p>
  5. <script>
  6. $(document).ready(function(){
  7. $("#test").click(function(){
  8. alert("JQUERY");
  9. var e=$("div");//定义了两jquery对象
  10. var w=$("div");//e是不等于w的。
  11. //首先使用data([key],[value])用法。
  12. $(e).data("a","aaaa");//分别在e和w上保存Key一样的数据,
  13. $(w).data("a","wwww");// 看它是否会覆盖前面的,虽然是保存在不同对象上。
  14. alert($(e).data("a"));//你猜到答案了吗,里输出是wwww;是不是有点意外?
  15. alert(e===w)//false
  16. alert($(w).data("a"));//这里也是wwww;
  17. //使用jQuery.data(element,[key],[value])来存放数据。
  18. $.data(e,"b","cccc");//分别在e和w上保存Key一样的数据,
  19. $.data(w,"b","dddd");// 看它是否会覆盖前面的,虽然是保存在不同对象上。
  20. alert($.data(e,"b"));//应该你能猜答案吧,输出cccc
  21. alert($.data(w,"b"));//这输出dddd
  22. });
  23. });
  24. </script>

看了上面的例子是不是发现data([key],[value])与jQuery.data(element,[key],[value])两个根本就不一样了对吧?它们之间到底有没有关系呢。怎么data([key],[value])会覆盖前面key相同的值呢?
而jQuery.data(element,[key],[value])只要是绑定到不同的对象上都不会造成覆盖。是这样吗?那来研究下它们的源代码吧。

先看jQuery.data(element,[key],[value])源代码。

Js代码  

  1. jQuery.extend({
  2. cache: {},
  3. // Please use with caution
  4. uuid: 0,
  5. // Unique for each copy of jQuery on the page
  6. // Non-digits removed to match rinlinejQuery
  7. expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
  8. ....
  9. data: function( elem, name, data, pvt /* Internal Use Only */ ) {
  10. // 是否可以附加数据,不可以则直接返回
  11. if ( !jQuery.acceptData( elem ) ) {
  12. return;
  13. }
  14. var privateCache, thisCache, ret,
  15. //jQuery.expando这是一个唯一的字符串,是这介jquery对象产生的时候就生成了。
  16. internalKey = jQuery.expando,
  17. getByName = typeof name === "string",
  18. // 必须区分处理DOM元素和JS对象,因为IE6-7不能垃圾回收对象跨DOM对象和JS对象进行的引用属性
  19. isNode = elem.nodeType,
  20. // 如果是DOM元素,则使用全局的jQuery.cache
  21. // 如果是JS对象,则直接附加到对象上
  22. cache = isNode ? jQuery.cache : elem,
  23. // Only defining an ID for JS objects if its cache already exists allows
  24. // the code to shortcut on the same path as a DOM node with no cache
  25. id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
  26. isEvents = name === "events";
  27. // 避免做更多的不必要工作,当尝试在一个没有任何数据的对象上获取数据时
  28. // 对象没有任何数据,直接返回
  29. if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
  30. return;
  31. }
  32. // id不存在的话就生成一个
  33. if ( !id ) {
  34. // Only DOM nodes need a new unique ID for each element since their data
  35. // ends up in the global cache
  36. if ( isNode ) {
  37. // 如果是DOM元素则在元素上产生唯一的ID 并且以jQuery.expando
  38. //为属性值为id保存在elem元素上,以便以后再根据jQuery.expando来查找ID。
  39. elem[ internalKey ] = id = ++jQuery.uuid;
  40. } else {
  41. // JS对象则直接使用jQuery.expando,既然是直接附加到对象上,又何必要id呢?
  42. // 避免与其他属性冲突!
  43. id = internalKey;
  44. }
  45. }
  46. //// 当我们试着访问一个键是否含有值的时候,如果不存在jQuery.cache[id]值,
  47. // 初始化jQuery.cache[id]值 为一个空对象{}
  48. if ( !cache[ id ] ) {
  49. cache[ id ] = {};
  50. if ( !isNode ) {
  51. cache[ id ].toJSON = jQuery.noop;
  52. }
  53. }
  54. // An object can be passed to jQuery.data instead of a key/value pair; this gets
  55. // shallow copied over onto the existing cache
  56. // data是接收对象和函数,浅拷贝
  57. if ( typeof name === "object" || typeof name === "function" ) {
  58. if ( pvt ) {
  59. cache[ id ] = jQuery.extend( cache[ id ], name );
  60. } else {
  61. cache[ id ].data = jQuery.extend( cache[ id ].data, name );
  62. }
  63. }
  64. / 存储对象,存放了所有数据的映射对象
  65. privateCache = thisCache = cache[ id ];
  66. // jQuery data() is stored in a separate object inside the object‘s internal data
  67. // cache in order to avoid key collisions between internal data and user-defined
  68. // data.
  69. // jQuery内部数据存在一个独立的对象(thisCache.data==thisCache[ internalKey ])
  70. //上,为了避免内部数据和用户定义数据冲突
  71. if ( !pvt ) {
  72. // 存放私有数据的对象不存在,则创建一个{}
  73. if ( !thisCache.data ) {
  74. thisCache.data = {};
  75. }
  76. // 使用私有数据对象替换thisCache
  77. thisCache = thisCache.data;
  78. }
  79. // 如果data不是undefined,表示传入了data参数,则存储data到name属性上
  80. if ( data !== undefined ) {
  81. // jQuery.camelCase( name )作用是如果传入的是object/function,不做转换,
  82. //只有传入的name是字符串才会转换。所以最终保存下来的是key/value对;
  83. thisCache[ jQuery.camelCase( name ) ] = data;
  84. }
  85. //从这以后下面的代码都是处理data: function( elem, name)data为空,求返回值data的情况了。
  86. if ( isEvents && !thisCache[ name ] ) {
  87. return privateCache.events;
  88. }
  89. // 如果name是字符串,则返回data
  90. // 如果不是,则返回整个存储对象
  91. if ( getByName ) {
  92. // First Try to find as-is property data
  93. ret = thisCache[ name ];
  94. // Test for null|undefined property data
  95. if ( ret == null ) {
  96. // Try to find the camelCased property
  97. ret = thisCache[ jQuery.camelCase( name ) ];
  98. }
  99. } else {
  100. ret = thisCache;
  101. }
  102. return ret;
  103. },
  104. ............
  105. });

请看图。

看jQuery.data(element,[key],[value])源代码后可以知道,每一个element都会有自己的一个{key:value}对象保存着数据,所以新建的对象就算有key相同它也不会覆盖原来存在的对象key所对应的value,因为新对象保存是是在另一个{key:value}对象中。

接下来要分析data([key],[value])源代码使用到了each(callback),在分析它之前先看下each(callback)用法和源代码。

Js代码  

  1. <div id="test2" onclick="test()">test2</div>
  2. <div id="abc3" onclick="test()">test3</div>
  3. <div id="test" onclick="test()">test</div>
  4. <p id="ttt">aaaa</p>
  5. <script>
  6. $(document).ready(function(){
  7. $("#test").click(function(){
  8. alert("JQUERY");
  9. var i=0;
  10. $("#abc3").each(function() {
  11. alert(++i);//只输出1;因为只有一个<div id="abc3">
  12. });
  13. alert("----");
  14. var j=0;
  15. $("div").each(function() {
  16. alert(++j);//分别输出1,2,3;因为有三个<div>所以循环三遍
  17. });
  18. });
  19. });
  20. </script>
  21. 现在来看each方法的具体实现如下:
  22. jQuery.fn = jQuery.prototype = {
  23. each: function( callback, args ) {
  24. return jQuery.each( this, callback, args );
  25. }
  26. }
  27. 可以看到它返回的是全局的each方法,并且将自身jQuery对象做为参数给它,全局的each方法的具体实现如下:
  28. // args 作为内部成员的调用来使用
  29. each: function( object, callback, args ) {
  30. var name, i = 0, length = object.length;  // 当object为jQuery对象时,length非空
  31. if ( args ) {
  32. if ( length === undefined ) {
  33. for ( name in object )
  34. if ( callback.apply( object[ name ], args ) === false )
  35. break;
  36. } else
  37. for ( ; i < length; )
  38. if ( callback.apply( object[ i++ ], args ) === false )
  39. break;
  40. // 以下是客户端程序进行调用
  41. } else {
  42. if ( length === undefined ) {
  43. for ( name in object )
  44. if ( callback.call( object[ name ], name, object[ name ] ) === false )
  45. break;
  46. } else
  47. // i表示索引值,value表示DOM元素
  48. for ( var value = object[0];
  49. i < length && callback.call( value, i, value ) !== false;
  50. value = object[++i] ){}
  51. }
  52. return object;
  53. }

现在我们关注下 for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} 这句代码;其中object[0]取得jQuery对象中的第一个DOM元素,通过for循环,
得到遍历整个jQuery对象中对应的每个DOM元素,通过callback.call( value,i,value); 将callback的this对象指向value对象,并且传递两个参数,i表示索引值,value表示DOM元素;其中callback是类似于 function(index, elem) { } 的方法。所以就得到 $("").each(function(index, elem){ });

再来看看data([key],[value])的源代码。

Js代码  

  1. jQuery.fn.extend({
  2. data: function( key, value ) {
  3. var parts, part, attr, name, l,
  4. elem = this[0],
  5. i = 0,
  6. data = null;
  7. // Gets all values
  8. if ( key === undefined ) {
  9. .....//处理没有Key的情况,这里不是我们要讨论的
  10. return data;
  11. }
  12. // Sets multiple values
  13. if ( typeof key === "object" ) {
  14. return this.each(function() {
  15. jQuery.data( this, key );
  16. });
  17. }
  18. parts = key.split( ".", 2 );
  19. parts[1] = parts[1] ? "." + parts[1] : "";
  20. part = parts[1] + "!";
  21. return jQuery.access( this, function( value ) {
  22. if ( value === undefined ) {
  23. 。。。//这里是没有value时,是索取返回值的情况,这不是我们讨论
  24. }
  25. parts[1] = value;
  26. //如果我使用用$("div").data("a","aaa")),下面调用each前的this指的是$("div")这返回的对象,
  27. this.each(function() {//注意了,这里是以每一个匹配的元素作为上下文来执行一个函数
  28. var self = jQuery( this );
  29. self.triggerHandler( "setData" + part, parts );
  30. //这里在元素上存放数据,本质还是委托data(element,[key],[value])来做的。
  31. //看前面有分析过了。
  32. //下面data( this, key, value )里的this指的是遍历整个jQuery对象中对应的每个DOM元素
  33. //$("div")它对应页面中一个<div>数组。
  34. jQuery.data( this, key, value )<span style="#ffcc00;">;//这名句会被循环多次执行,也就是保存数据</span>。
  35. //这里就是核心一句话。但要清楚看上面了它是在each(functipn(){})中的。
  36. self.triggerHandler( "changeData" + part, parts );
  37. });
  38. }, null, value, arguments.length > 1, null, false );
  39. },
  40. //在元素上移除存放的数据。具体实现如下:
  41. removeData: function( key ) {
  42. return this.each(function() {
  43. jQuery.removeData( this, key );
  44. });
  45. }
  46. });

如果对于data([key],[value])的源代码不是很了解,好吧,我就用一个例子来模仿实现它吧。

Js代码  

  1. <div id="test2" onclick="test()">test2</div>
  2. <div id="abc3" onclick="test()">test3</div>
  3. <div id="test" onclick="test()">test</div>
  4. <p id="ttt">aaaa</p>
  5. <script>
  6. $(document).ready(function(){
  7. $("#test").click(function(){
  8. alert("JQUERY");
  9. var i=0;
  10. $("#abc3").each(function() {
  11. alert(++i);//只输出1;因为只有一个<div id="abc3">
  12. });
  13. alert("----");
  14. var j=1;
  15. $("div").each(function() {//以每一个匹配的元素作为上下文来执行这个函数
  16. $.data(this,"a","wwww");//这里的this就是指$("div"),
  17. //分别遍历每一个匹配的元素给它们每一个对象{}都保存一个key/value
  18. alert(j++);//分别输出1 ,2 ,3 因为有三个<div>元素
  19. });
  20. alert($("#test").data("a"));//返回wwww,
  21. //是不是很惊呀,我没有保存在它身上啊,怎么也有值,很明显是它是查这个div节点上有没有,
  22. //肯定是有值了,因为上面给循环保存在div这Dom结点上了。
  23. alert($("#test")===$("div"));//false证明两新建的对象不是同一个。
  24. alert($("div").data("a"));//返回wwww,
  25. //这里也是一样因为是div节点上都保存了"a"="wwww"这样一个键值对了。
  26. });
  27. });
  28. </script>

现在对data([key],[value])与jQuery.data(element,[key],[value])都有了解了吧,如果还是半懂,再回头多看一遍,耐心地理解一下。其实表面上很不一样。但本质上还是有联系的,现在明白原理后就可以请放心地使用了。jQuery.data(element,[key],[value])只把数据绑定到参数element节点上。data([key],[value])
    如$("div").data("a","aaaa")它是把数据绑定每一个匹配div节点的元素上。
    附加说明下,文中所分析用到的是jquery-1.7.2.js的源代码。如果你想了解更多请自行去下载哈。

5 

0 

分享到:  

剖析XMLHttpRequest对象Hibernate 面试中最常考察的知识点整合

评论

5 楼 逆寒刀 2014-03-17

颇为耐心的一片文章,很细致,谢谢分享

4 楼 ysyong 2013-11-04

这文章太啰嗦了,直接一个$.each不就说明了问题吗?

3 楼 zyc199144 2013-09-16

谢谢分享,学习了。

2 楼 jianfulove 2013-05-21

aboutibm 写道

原帖地址
http://www.software8.co/wzjs/jquery/3731.html

时间: 2024-10-14 08:15:39

jQuery对象数据缓存Cache原理及jQuery.data详解的相关文章

jQuery.data的是jQuery的数据缓存系统

jQuery.Data源码 jQuery.data的是jQuery的数据缓存系统.它的主要作用就是为普通对象或者DOM元素添加数据. 1 内部存储原理 这个原理很简单,原本要添加在DOM元素本身的数据,现在被集中的存储在cache集合中.它们之间靠一个从1开始的数字键来联系着.这样DOM元素就不会像以前那么笨重了,更不会出现以前那种循环引用而引起的内存泄漏.现在DOM只需要保存好这个数字键值即可.这个属性值被保存在DOM元素的一个属性里,该属性名是由jQuery.expando生成的. 2 Da

2.应用数据缓存-Cache

2.应用数据缓存-Cache 1.引入CacheHelper.cs CacheHelper.cs文件源码在下面; 2.介绍用法: //键 string ips = "键"; //值;得到当前时间 long Now_time = DateTime.Now.ToFileTime(); //存;设置过期缓存时间2s;键值对形式存入;Insert方法存入 CacheHelper.SetCache(ips, Now_time,TimeSpan.FromSeconds(2)); //取;通过键取值

TimesTen 应用层数据库缓存学习:17. 全局数据缓存(cache grid)的高可用性

概述 本文有两个目的: 1. 介绍TimesTen Global Cache Grid的高可用性 2. 给出了一个简单的建立和清理Global Cache Grid的过程,前面已经有一篇文章: TimesTen 应用层数据库缓存学习:13. 全局数据缓存(cache grid),但那个Cache Group太复杂 建立一个简单的Global Cache Grid 首先建立两个TimesTen instance,一个为tt1122, 一个为ttnew. 之所以建立两个实例,是为了停instance

JQuery对象转dom ,dom转jQuery

jquery对象转换成 dom对象jquery提供了两种方法将一个jquery对象转换成一个dom对象,即[index]和get(index).可能有人会觉得奇怪,怎么是用下标呢,没错,jquery对象就是一个数组对象.下面代码将演示一个jquery对象转换成dom对象,再使用dom对象的方法复制代码 代码如下: var $cr=$("#cr"); //jquery对象var cr = $cr[0]; //dom对象 也可写成 var cr=$cr.get(0);alert(cr.ch

jQuery height()、innerHeight()、outerHeight()函数的区别详解

jQuery height().innerHeight().outerHeight()函数的区别详解 在jQuery中,获取元素高度的函数有3个,它们分别是height(). innerHeight().outerHeight(). 与此相对应的是,获取元素宽度的函数也有3个,它们分别是width(). innerWidth().outerWidth(). 在这里,我们以height().innerHeight().outerHeight()3个函数为例,来详细介绍它们之间的区别. 下面我们以元

java多线程模式ThreadLocal原理简述及其使用详解

原创整理不易,转载请注明出处:java多线程模式ThreadLocal原理简述及其使用详解 代码下载地址:http://www.zuidaima.com/share/1781557457128448.htm ThreadLocal是为了使每个线程保存一份属于自己的数据. 先看一个使用ThreadLocal的实例. package com.zuidaima.aop.framework; import com.zuidaima.core.NamedThreadLocal; public abstra

使用LVS实现负载均衡原理及安装配置详解

转:http://www.cnblogs.com/liwei0526vip/p/6370103.html 使用LVS实现负载均衡原理及安装配置详解 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F5.Netscale.这里主要是学习 LVS 并对其进行了详细的总结记录. 一.负载均衡LVS基本介绍 LB集群的架构和原理很简单,就是当用户的请求过来时,会直接分发到Director

使用 LVS 实现负载均衡原理及安装配置详解

使用 LVS 实现负载均衡原理及安装配置详解 来源:肖邦linux 发布时间:2017-02-19 阅读次数:106 0 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F5.Netscale.这里主要是学习 LVS 并对其进行了详细的总结记录. 一.负载均衡LVS基本介绍 LB集群的架构和原理很简单,就是当用户的请求过来时,会直接分发到Director Server上,然后它把用

FTP服务器工作原理的及配置详解

FTP服务器工作原理的及配置详解 FTP工作原理概述 FTP:file transfer protocol 它也是一个C/S架构的服务.server:监听在套接字21/tcp端口.按照套接字监听工作状态可以分为两类: 命令连接:发送文件管理类命令,始终处于连接状态,始终监听在21/tcp端口. 数据连接:主要是实现数据传输,这种连接是按需连接的,而且在传输结束会立刻中断. 对于数据连接还有两种不同的工作模式: 主动工作的模式:服务器根据监听在21端口接收到的命令,使用自己的20号端口,将数据传输