Heim  >  Artikel  >  Web-Frontend  >  关于jQuery对象数据缓存Cache原理以及jQuery.data详解_jquery

关于jQuery对象数据缓存Cache原理以及jQuery.data详解_jquery

WBOY
WBOYOriginal
2016-05-16 17:38:091229Durchsuche

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

Js代码:

复制代码 代码如下:

test2

test3

test

aaaa


<script> <BR>$(document).ready(function(){ <BR>$("#test").click(function(){ <BR>alert("JQUERY"); <br><br>var e=$("div");//定义了两jquery对象 <BR>var w=$("div");//e是不等于w的。 <br><br>//首先使用data([key],[value])用法。 <BR>$(e).data("a","aaaa");//分别在e和w上保存Key一样的数据, <BR>$(w).data("a","wwww");// 看它是否会覆盖前面的,虽然是保存在不同对象上。 <BR>alert($(e).data("a"));//你猜到答案了吗,里输出是wwww;是不是有点意外? <BR>alert(e===w)//false <BR>alert($(w).data("a"));//这里也是wwww; <br><br>//使用jQuery.data(element,[key],[value])来存放数据。 <BR>$.data(e,"b","cccc");//分别在e和w上保存Key一样的数据, <BR>$.data(w,"b","dddd");// 看它是否会覆盖前面的,虽然是保存在不同对象上。 <BR>alert($.data(e,"b"));//应该你能猜答案吧,输出cccc <BR>alert($.data(w,"b"));//这输出dddd <br><br>}); <BR>}); <BR></script>

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

Js代码:

复制代码 代码如下:

jQuery.extend({
cache: {},

// Please use with caution
uuid: 0,

// Unique for each copy of jQuery on the page
// Non-digits removed to match rinlinejQuery
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),

....
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
// 是否可以附加数据,不可以则直接返回
if ( !jQuery.acceptData( elem ) ) {
return;
}

var privateCache, thisCache, ret,
//jQuery.expando这是一个唯一的字符串,是这介jquery对象产生的时候就生成了。
internalKey = jQuery.expando,
getByName = typeof name === "string",

// 必须区分处理DOM元素和JS对象,因为IE6-7不能垃圾回收对象跨DOM对象和JS对象进行的引用属性
isNode = elem.nodeType,

// 如果是DOM元素,则使用全局的jQuery.cache
// 如果是JS对象,则直接附加到对象上
cache = isNode ? jQuery.cache : elem,

// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
isEvents = name === "events";

// 避免做更多的不必要工作,当尝试在一个没有任何数据的对象上获取数据时
// 对象没有任何数据,直接返回
if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
// id不存在的话就生成一个
if ( !id ) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
// 如果是DOM元素则在元素上产生唯一的ID 并且以jQuery.expando
//为属性值为id保存在elem元素上,以便以后再根据jQuery.expando来查找ID。
elem[ internalKey ] = id = ++jQuery.uuid;
} else {
// JS对象则直接使用jQuery.expando,既然是直接附加到对象上,又何必要id呢?
// 避免与其他属性冲突!
id = internalKey;
}
}

//// 当我们试着访问一个键是否含有值的时候,如果不存在jQuery.cache[id]值,
// 初始化jQuery.cache[id]值 为一个空对象{}
if ( !cache[ id ] ) {
cache[ id ] = {};

if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
}

// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
// data是接收对象和函数,浅拷贝
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
/ 存储对象,存放了所有数据的映射对象
privateCache = thisCache = cache[ id ];

// jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
// jQuery内部数据存在一个独立的对象(thisCache.data==thisCache[ internalKey ])
//上,为了避免内部数据和用户定义数据冲突
if ( !pvt ) {
// 存放私有数据的对象不存在,则创建一个{}
if ( !thisCache.data ) {
thisCache.data = {};
}
// 使用私有数据对象替换thisCache
thisCache = thisCache.data;
}
// 如果data不是undefined,表示传入了data参数,则存储data到name属性上
if ( data !== undefined ) {
// jQuery.camelCase( name )作用是如果传入的是object/function,不做转换,
//只有传入的name是字符串才会转换。所以最终保存下来的是key/value对;
thisCache[ jQuery.camelCase( name ) ] = data;
}

//从这以后下面的代码都是处理data: function( elem, name)data为空,求返回值data的情况了。

if ( isEvents && !thisCache[ name ] ) {
return privateCache.events;
}

// 如果name是字符串,则返回data
// 如果不是,则返回整个存储对象
if ( getByName ) {

// First Try to find as-is property data
ret = thisCache[ name ];

// Test for null|undefined property data
if ( ret == null ) {

// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}

return ret;
},
............
});

请看图。

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

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

Js代码:

复制代码 代码如下:

test2

test3

test

aaaa


<script> <BR>$(document).ready(function(){ <BR>$("#test").click(function(){ <BR>alert("JQUERY"); <br><br>var i=0; <BR>$("#abc3").each(function() { <BR>alert(++i);//只输出1;因为只有一个<div id="abc3"> <BR>}); <BR>alert("----"); <BR>var j=0; <BR>$("div").each(function() { <BR>alert(++j);//分别输出1,2,3;因为有三个<div>所以循环三遍 <BR>}); <BR>}); <BR>}); <BR></script>

现在来看each方法的具体实现如下:
jQuery.fn = jQuery.prototype = {
each: function( callback, args ) {
return jQuery.each( this, callback, args );
}
}

可以看到它返回的是全局的each方法,并且将自身jQuery对象做为参数给它,全局的each方法的具体实现如下:
// args 作为内部成员的调用来使用
each: function( object, callback, args ) {
var name, i = 0, length = object.length; // 当object为jQuery对象时,length非空

if ( args ) {
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ], args ) === false )
break;
} else
for ( ; i if ( callback.apply( object[ i++ ], args ) === false )
break;
// 以下是客户端程序进行调用
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
// i表示索引值,value表示DOM元素
for ( var value = object[0];
i value = object[++i] ){}
}

return object;
}

现在我们关注下 for ( var value = object[0]; i 得到遍历整个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代码:

复制代码 代码如下:

jQuery.fn.extend({
data: function( key, value ) {
var parts, part, attr, name, l,
elem = this[0],
i = 0,
data = null;

// Gets all values
if ( key === undefined ) {
.....//处理没有Key的情况,这里不是我们要讨论的

return data;
}

// Sets multiple values
if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}

parts = key.split( ".", 2 );
parts[1] = parts[1] ? "." + parts[1] : "";
part = parts[1] + "!";

return jQuery.access( this, function( value ) {

if ( value === undefined ) {
。。。//这里是没有value时,是索取返回值的情况,这不是我们讨论
}

parts[1] = value;

//如果我使用用$("div").data("a","aaa")),下面调用each前的this指的是$("div")这返回的对象,
this.each(function() {//注意了,这里是以每一个匹配的元素作为上下文来执行一个函数
var self = jQuery( this );

self.triggerHandler( "setData" + part, parts );

//这里在元素上存放数据,本质还是委托data(element,[key],[value])来做的。
//看前面有分析过了。
//下面data( this, key, value )里的this指的是遍历整个jQuery对象中对应的每个DOM元素
//$("div")它对应页面中一个
数组。
jQuery.data( this, key, value );//这名句会被循环多次执行,也就是保存数据
//这里就是核心一句话。但要清楚看上面了它是在each(functipn(){})中的。
self.triggerHandler( "changeData" + part, parts );
});
}, null, value, arguments.length > 1, null, false );
},
//在元素上移除存放的数据。具体实现如下:
removeData: function( key ) {
return this.each(function() {
jQuery.removeData( this, key );
});
}
});

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

Js代码:

复制代码 代码如下:

test2

test3

test

aaaa


<script> <BR>$(document).ready(function(){ <BR>$("#test").click(function(){ <BR>alert("JQUERY"); <br><br>var i=0; <BR>$("#abc3").each(function() { <BR>alert(++i);//只输出1;因为只有一个<div id="abc3"> <BR>}); <BR>alert("----"); <BR>var j=1; <BR>$("div").each(function() {//以每一个匹配的元素作为上下文来执行这个函数 <br><br>$.data(this,"a","wwww");//这里的this就是指$("div"), <BR>//分别遍历每一个匹配的元素给它们每一个对象{}都保存一个key/value <BR>alert(j++);//分别输出1 ,2 ,3 因为有三个<div>元素 <BR>}); <BR>alert($("#test").data("a"));//返回wwww, <BR>//是不是很惊呀,我没有保存在它身上啊,怎么也有值,很明显是它是查这个div节点上有没有, <BR>//肯定是有值了,因为上面给循环保存在div这Dom结点上了。 <BR>alert($("#test")===$("div"));//false证明两新建的对象不是同一个。 <br><br>alert($("div").data("a"));//返回wwww, <BR>//这里也是一样因为是div节点上都保存了"a"="wwww"这样一个键值对了。 <BR>}); <BR>}); <BR></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的源代码。下载地址:http://demo.jb51.net/jslib/jquery/jquery-1.7.2.min.js

 

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn