最近在研究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()源码进行详细剖析,有兴趣的我们可以在下篇见。