jQuery数据缓存Cache及$("").data([key],[value])与jQuery.data(element,[key],[value])的区别
2013-10-27 12:52 阅读(178)

最近在研究dwz时,发现其中普遍用到了jQuery.data()数据缓存,了解了下,对$("").data([key],[value])和jQuery.data(element,[key],[value])的区别分辨不清,所以就深入研究了下。与大家分享。

有俩种添加缓存的方法$("").data([key],[value])和jQuery.data(element,[key],[value]),初学时很容易让人混淆,尤其是给dom元素添加缓存数据时。这里用一句话简单总结下:

jQuery.data(element,[key],[value])是个基础方法,可以实现为dom元素或js对象添加缓存, 而$("").data([key],[value])其实是对前者的扩展,其目的是可以方便的通过选择器为多个dom元素添加缓存数据,如 $(".grey").data([key],[value]),为所有类样式为grey的元素添加缓存$("").data([key],[value])内部也是通过调用jQuery.data(element,[key],[value])来实现的。

首先,看个典型的容易混淆的例子,之后在慢慢剖析下。

<body>
<div id="con">
</div>
<div id="con1">
</div>
 $("#con").data("key11","aaaa");//为id为con的div添加缓存数据
 var con11 = $("#con").data("key11");//在获得下,此时con11为 "aaaa",  这个理所当然
	 
 $.data($("#con"),"key11","aaaa"); //采用第二种方式,为id为con的div添加数据
 var con22 = $.data($("#con"),"key11");//在获得下, 此时con22的值为undefined。为啥那, 值去哪了,
在解答上面的疑问前,我们在做个测试,目的是弄清楚添加的数据是怎么存放到对象中的以及放到哪了:  
var obj = {};//定义个普通的js对象
  $.data(obj,"key11","aaaa"); //用第二种方法为这个对象添加数据
  var con22 = $.data(obj,"key11");//此时con22的值为 "aaaa", 正确的取到了。


debug下,看看这个obj对象中发生了什么:


多了个属性名为:jQuery16403094002134166658  的对象,而这个对象中恰恰存着我们上面赋值的数据(key11"aaaa")

在看个例子: 

var dom_obj = document.getElementById("con");//获得个普通的dom元素
 $.data(dom_obj,"key11","aaaa");//为这个dom元素添加数据
 var con22 = $.data(dom_obj,"key11");//con22值为''aaaa" , 同样获得了数据
debug下:


此时dom_obj 中也多了个属性jQuery164007486486807465553,只不过其对应的不再是一个能存放缓存数据的对象,而是一个索引1。也就是说缓存数据放在了别的地方。实际上是放在了jquery的一个全局对象cache中,如下:


uuid 是用于创建索引的,每次通过++uuid获得新的索引。expando用于生成jQuery164007486486807465553的,是个随机码,每次jquery文件被加载时被生成,而一旦生成,整个页面(html页面)就会共用这个码。

debug看下cache中的情况:


一目了然了。


通过上面俩个实例我们不难发现对于 jQuery.data(element,[key],[value]) 方式为element添加缓存数据是区分俩种形式的对象:js对象、dom元素

   1。如果是为js对象添加缓存数据, jquery会将这些缓存数据封装个新的对象中,然后将这个新的对象赋到上面js对象的特定属性中(如:jQuery164007486486807465553),也就是说这些缓存数据最终是存放到这个js对象本身中的。

  2。如果是为dom元素添加缓存数据, jquery也会将这些缓存数据封装个新的对象中, 但是却将这个新的对象放到个全局的cache中,而将索引放到这个dom元素中。当要获得缓存的数据时只需通过这个索引到cache中找到相应的对象即可。所以对于文章开头的那个例子:

$.data($("#con"),"key11","aaaa"); //此时会将索引放到$("#con")返回的对象中,注意,此时$("#con")的返回值被看成是个普通的js对象。
var con22 = $.data($("#con"),"key11");//而此时$("#con")返回的又是个新的对象,其中根本不会有存放的索引,自然也就找不到相应的缓存对象
可以改为如下:

var jquery_obj = $("#con");
$.data(jquery_obj,"key11","aaaa");
 var con22 = $.data(jquery_obj,"key11");//此时con22的值为"aaaa"
但是注意这样写并不能为id为"con"的dom元素添加缓存,而只是为$("#con")返回的对象添加缓存。 应该写成:$.data(document.getElementById("con"),"key11","aaaa"); 或者使用即将说到的的$("").data([key],[value])方式,如下:

 $("#con").data("key11","aaaa")


文章开头我们说过$("").data([key],[value])是专门用于为jquery选择器选择的dom元素添加缓存,也可以说是专门为dom元素添加缓存数据的。我们知道jquery选择器返回的结果是个集合(准确说是个数据),$("").data([key],[value])会将缓存数据分别赋到集合的每个元素中,他先将集合中的元素从jquery对象形式转为普通dom对象形式,然后再调用jQuery.data(element,[key],[value])。测试下:

$("#con").data("key11","aaaa");
var con22 = $.data(document.getElementById("con"),"key11");//此时con22为"aaaa",说明索引确实在dom元素中

下面从$("").data([key],[value])源码来分析下他的原理, 而对于jQuery.data(element,[key],[value])的源码会在下篇中详细说:

data: function( key, value ) {
		var data = null;
                //key为空时,我们不用关心
		if ( typeof key === "undefined" ) {
			if ( this.length ) {
				data = jQuery.data( this[0] );

				if ( this[0].nodeType === 1 ) {
			    var attr = this[0].attributes, name;
					for ( var i = 0, l = attr.length; i < l; i++ ) {
						name = attr[i].name;

						if ( name.indexOf( "data-" ) === 0 ) {
							name = jQuery.camelCase( name.substring(5) );

							dataAttr( this[0], name, data[ name ] );
						}
					}
				}
			}

			return data;

		} else if ( typeof key === "object" ) {
			return this.each(function() {
				jQuery.data( this, key );
			});
		}
                
		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";
                //value为空时,获取缓存数据
		if ( value === undefined ) {
			data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			// Try to fetch any internally stored data first
			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
				data = dataAttr( this[0], key, data );
			}

			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;

		} else {//设置缓存数据
			return this.each(function() {//遍历jquery选择器获得的集合
				var $this = jQuery( this ),//此时的this为转换后的dom对象
					args = [ parts[0], value ];

				$this.triggerHandler( "setData" + parts[1] + "!", args );
                                //调用jQuery.data(element,[key],[value])方法设置数据
				jQuery.data( this, key, value );
				$this.triggerHandler( "changeData" + parts[1] + "!", args );
			});
		}
	},



通过分析不难总结出:

$("").data([key],[value])   适用于为dom元素添加缓存数据,而jQuery.data(element,[key],[value])适用于为js对象添加缓存。


下篇文章中我会将$("").data([key],[value])和jQuery.data(element,[key],[value])的源码以及jquery.each()源码进行详细剖析,有兴趣的我们可以在下篇见。