jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍


Posted in Javascript onApril 07, 2013

网上有很多教你怎么使用jQuery.data(..)来实现数据缓存,但有两个用户经常使用的data([key],[value])和jQuery.data(element,[key],[value])几乎没有什么文章说清楚它们两的区别,所以我用到了,研究下分享给大家。

$("").data([key],[value])与jQuery.data(element,[key],[value])的区别
这两个函数都是用来在元素上存放数据也就平时所说的数据缓存,都返回jQuery对象,当时我分别在使用它俩的时候真的吓我一跳,区别可大了,真是不用不知道,一用吓一跳。看例子先吧,后再根据源代码分析。

Js代码:

<div id="test2" onclick="test()">test2</div> 
<div id="abc3" onclick="test()">test3</div> 
<div id="test" onclick="test()">test</div> 
<p id="ttt">aaaa</p> 
<script> 
$(document).ready(function(){ 
$("#test").click(function(){ 
alert("JQUERY"); 
var e=$("div");//定义了两jquery对象 
var w=$("div");//e是不等于w的。 
//首先使用data([key],[value])用法。 
$(e).data("a","aaaa");//分别在e和w上保存Key一样的数据, 
$(w).data("a","wwww");// 看它是否会覆盖前面的,虽然是保存在不同对象上。 
alert($(e).data("a"));//你猜到答案了吗,里输出是wwww;是不是有点意外? 
alert(e===w)//false 
alert($(w).data("a"));//这里也是wwww; 
//使用jQuery.data(element,[key],[value])来存放数据。 
$.data(e,"b","cccc");//分别在e和w上保存Key一样的数据, 
$.data(w,"b","dddd");// 看它是否会覆盖前面的,虽然是保存在不同对象上。 
alert($.data(e,"b"));//应该你能猜答案吧,输出cccc 
alert($.data(w,"b"));//这输出dddd 
}); 
}); 
</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对象数据缓存Cache原理及jQuery.data方法区别介绍 
看jQuery.data(element,[key],[value])源代码后可以知道,每一个element都会有自己的一个{key:value}对象保存着数据,所以新建的对象就算有key相同它也不会覆盖原来存在的对象key所对应的value,因为新对象保存是是在另一个{key:value}对象中。

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

Js代码:

<div id="test2" onclick="test()">test2</div> 
<div id="abc3" onclick="test()">test3</div> 
<div id="test" onclick="test()">test</div> 
<p id="ttt">aaaa</p> 
<script> 
$(document).ready(function(){ 
$("#test").click(function(){ 
alert("JQUERY"); 
var i=0; 
$("#abc3").each(function() { 
alert(++i);//只输出1;因为只有一个<div id="abc3"> 
}); 
alert("----"); 
var j=0; 
$("div").each(function() { 
alert(++j);//分别输出1,2,3;因为有三个<div>所以循环三遍 
}); 
}); 
}); 
</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 < length; ) 
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 < length && callback.call( value, i, value ) !== false; 
value = object[++i] ){} 
} 
return object; 
}

现在我们关注下 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代码:
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")它对应页面中一个<div>数组。 
jQuery.data( this, key, value )<span style="background-color: #ffcc00;">;//这名句会被循环多次执行,也就是保存数据</span>。 
//这里就是核心一句话。但要清楚看上面了它是在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代码:
<div id="test2" onclick="test()">test2</div> 
<div id="abc3" onclick="test()">test3</div> 
<div id="test" onclick="test()">test</div> 
<p id="ttt">aaaa</p> 
<script> 
$(document).ready(function(){ 
$("#test").click(function(){ 
alert("JQUERY"); 
var i=0; 
$("#abc3").each(function() { 
alert(++i);//只输出1;因为只有一个<div id="abc3"> 
}); 
alert("----"); 
var j=1; 
$("div").each(function() {//以每一个匹配的元素作为上下文来执行这个函数 
$.data(this,"a","wwww");//这里的this就是指$("div"), 
//分别遍历每一个匹配的元素给它们每一个对象{}都保存一个key/value 
alert(j++);//分别输出1 ,2 ,3 因为有三个<div>元素 
}); 
alert($("#test").data("a"));//返回wwww, 
//是不是很惊呀,我没有保存在它身上啊,怎么也有值,很明显是它是查这个div节点上有没有, 
//肯定是有值了,因为上面给循环保存在div这Dom结点上了。 
alert($("#test")===$("div"));//false证明两新建的对象不是同一个。 
alert($("div").data("a"));//返回wwww, 
//这里也是一样因为是div节点上都保存了"a"="wwww"这样一个键值对了。 
}); 
}); 
</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.3water.com/jslib/jquery/jquery-1.7.2.min.js
Javascript 相关文章推荐
Jquery下attr和removeAttr的使用方法
Dec 28 Javascript
Javascript控制页面链接在新窗口打开具体方法
Aug 16 Javascript
动态添加删除表格行的js实现代码
Feb 28 Javascript
使用JavaScript获取电池状态的方法
May 03 Javascript
javascript实现动态统计图开发实例
Nov 21 Javascript
AngularJS基础 ng-mouseover 指令简单示例
Aug 02 Javascript
DOM操作原生js 的bug,使用jQuery 可以消除的解决方法
Sep 04 Javascript
javascript中获取元素标签中间的内容的实现方法
Oct 08 Javascript
在Node.js下运用MQTT协议实现即时通讯及离线推送的方法
Jan 24 Javascript
微信小程序npm引入vant-weapp的踩坑记录
Aug 01 Javascript
vue下使用nginx刷新页面404的问题解决
Aug 02 Javascript
微信小程序实现拍照和相册选取图片
May 09 Javascript
关于jQuery对象数据缓存Cache原理以及jQuery.data详解
Apr 07 #Javascript
有关于eclipse配置spket需要注意的一些地方
Apr 07 #Javascript
如何在一个页面显示多个百度地图
Apr 07 #Javascript
关于JS字符串函数String.replace()
Apr 07 #Javascript
有关于JS构造函数的重载和工厂方法
Apr 07 #Javascript
JS完成代码前最好对其做5件事
Apr 07 #Javascript
有关于JS辅助函数inherit()的问题
Apr 07 #Javascript
You might like
业余方法DIY电子管FM收音机
2021/03/02 无线电
PHP 字符串正则替换函数preg_replace使用说明
2011/07/15 PHP
php数组相加 array(“a”)+array(“b”)结果还是array(“a”)
2012/09/19 PHP
php简单定时执行任务的实现方法
2015/02/23 PHP
php保存任意网络图片到服务器的方法
2015/04/14 PHP
谈谈php对接芝麻信用踩的坑
2016/12/01 PHP
laravel 5.5 关闭token的3种实现方式
2019/10/24 PHP
jQuery 注意事项 与原因分析
2009/04/24 Javascript
JavaScript模板引擎用法实例
2015/07/10 Javascript
WEB前端实现裁剪上传图片功能
2016/10/17 Javascript
微信小程序 wx:key详细介绍
2016/10/28 Javascript
Bootstrap CSS组件之下拉菜单(dropdown)
2016/12/17 Javascript
原生JS实现图片轮播效果
2016/12/26 Javascript
从源码看angular/material2 中 dialog模块的实现方法
2017/10/18 Javascript
详解vue-admin和后端(flask)分离结合的例子
2018/02/12 Javascript
npm配置国内镜像资源+淘宝镜像的方法
2018/09/07 Javascript
js回文数的4种判断方法示例
2019/06/04 Javascript
vue+koa2搭建mock数据环境的详细教程
2020/05/18 Javascript
vue3.0实现插件封装
2020/12/14 Vue.js
Python跳出循环语句continue与break的区别
2014/08/25 Python
零基础写python爬虫之使用urllib2组件抓取网页内容
2014/11/04 Python
Python Flask-web表单使用详解
2017/11/18 Python
django的登录注册系统的示例代码
2018/05/14 Python
解决Pycharm调用Turtle时 窗口一闪而过的问题
2019/02/16 Python
Python字符串逆序的实现方法【一题多解】
2019/02/18 Python
简单了解Python生成器是什么
2019/07/02 Python
django foreignkey外键使用的例子 相当于left join
2019/08/06 Python
Python3标准库之dbm UNIX键-值数据库问题
2020/03/24 Python
python中_del_还原数据的方法
2020/12/09 Python
html5本地存储 localStorage操作使用详解
2016/09/20 HTML / CSS
法国娇韵诗官方旗舰店:Clarins是来自法国的天然护肤品牌
2018/06/30 全球购物
物理力学求职信
2014/02/18 职场文书
自动一体化专业求职信
2014/03/15 职场文书
开业主持词
2014/03/21 职场文书
毕业生班级鉴定评语
2015/01/04 职场文书
2019年大学推荐信
2019/06/24 职场文书