jQuery对象数据缓存Cache原理及jQuery.data详解
网上有很多教你怎么使用jQuery.data(..)来实现数据缓存,但有两个用户经常使用的data([key],[value])和jQuery.data(element,[key],[value])几乎没有什么文章说清楚它们两的区别,所以我用到了,研究下分享给大家。
$("").data([key],[value])与jQuery.data(element,[key],[value])的区别
这两个函数都是用来在元素上存放数据也就平时所说的数据缓存,都返回jQuery对象,当时我分别在使用它俩的时候真的吓我一跳,区别可大了,真是不用不知道,一用吓一跳。看例子先吧,后再根据源代码分析。
- <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])源代码。
- 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)用法和源代码。
- <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])的源代码。
- 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="#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])的源代码不是很了解,好吧,我就用一个例子来模仿实现它吧。
- <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的源代码。如果你想了解更多请自行去下载
jQuery对象数据缓存Cache原理及jQuery.data详解的更多相关文章
- jQuery.data的是jQuery的数据缓存系统
jQuery.Data源码 jQuery.data的是jQuery的数据缓存系统 jQuery.data的是jQuery的数据缓存系统.它的主要作用就是为普通对象或者DOM元素添加数据. 1 内部存储 ...
- jQuery 源码分析(十) 数据缓存模块 data详解
jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...
- jQuery height()、innerHeight()、outerHeight()函数的区别详解
参考来源:http://www.jb51.net/article/84897.htm 代码示例(可复制到编辑器直接打开): <!DOCTYPE html> <html lang=&q ...
- [Spark内核] 第40课:CacheManager彻底解密:CacheManager运行原理流程图和源码详解
本课主题 CacheManager 运行原理图 CacheManager 源码解析 CacheManager 运行原理图 [下图是CacheManager的运行原理图] 首先 RDD 是通过 iter ...
- Android辅助功能原理与基本使用详解-AccessibilityService
辅助功能原理与基本使用详解 本文主要介绍辅助功能的使用 辅助功能基本原理 辅助功能基本配置和框架搭建 辅助功能实战解析 辅助功能基本原理 辅助功能(AccessibilityService)其实是 ...
- SQL Server 表的管理_关于数据增删查改的操作的详解(案例代码)
SQL Server 表的管理_关于数据增删查改的操作的详解(案例代码)-DML 1.SQL INSERT INTO 语句(在表中插入) INSERT INTO 语句用于向表中插入新记录. SQL I ...
- Nginx 反向代理工作原理简介与配置详解
Nginx反向代理工作原理简介与配置详解 by:授客 QQ:1033553122 测试环境 CentOS 6.5-x86_64 nginx-1.10.0 下载地址:http://nginx. ...
- (转)使用LVS实现负载均衡原理及安装配置详解
使用LVS实现负载均衡原理及安装配置详解 原文:https://www.cnblogs.com/liwei0526vip/p/6370103.html
- 图解大数据 | 海量数据库查询-Hive与HBase详解
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/84 本文地址:http://www.showmeai.tech/article-det ...
随机推荐
- FlashFXP Registration
-------- FlashFXP Registration Data START --------FLASHFXPuQBW1wi5uQAAAACvW7cJKQXzmx8Eu6ikXL4LbrYQHZ ...
- PowerShell~发布你的mvc网站
通过使用ps加上msbuild可以方便的编译你的.net应用程序,并且可以把它发布到你的磁盘上,部署非常方例! 我们在c盘添加一个hello网站,解决方案名是hello.sln,它的网站是hello. ...
- 在windows下编译出linux可执行程序
set GOARCH=amd64 set GOOS=linux go build xx.go 会生成一个没有后缀的xx二进制文件 将该文件放入linux系统某个文件夹下 赋予权限 chmod 777 ...
- HttpMessageNotWritableException异常解决办法
昨天做多对多的时遇到这个错误,网上找了一大堆,都没有解决掉,这个异常是说要解析的对象解析不了,就有可能该对象为null了,为了测试,我把数据库的数据都填上去 结果还是报错 看来是时候debug下 ...
- UVa OJ 458
The Decoder Write a complete program that will correctly decode a set of characters into a valid m ...
- 亲身经历,Java面试题整理
博主在2015年暑期参加过一些Java开发工程师实习的面试和笔试,在此将重点整理出来,以供大家学习. 资料1: 一.单继承 1.1Java类是否支持多重继承? 答:继承的基本原则是: 子类继承父类的所 ...
- ios https 安全证书配置
原定于2017年1月1日起所有提交到 App Store 的App必须强制开启 ATS,需要配置Https.但是现在不需要了,无固定期限的往后延期了,但是这个还是得弄明白下为好,说不定哪天突然就让弄了 ...
- Android 友盟和微信的包冲突:Multiple dex files define Lcom/tencent/a/a/a/a/a;
最近App中有个需求是添加微信支付,就在微信技术官网 http://open.weixin.qq.com,查看一下文档,然后下载SDk,Demo.把SDK集成进项目. 照着微信的文档,把jar包和进来 ...
- 使用 Azure ARM 部署Word Press 遇到 Extension节点 扩展的问题
在使用Azure ARM模式部署wordpress,将php网站压缩成zip的形式在DefaultTemplate模板中已扩展的形式实现安装 遇到的问题总结: 1.开始在sites节点中,resour ...
- ZIP解压缩文件的工具类【支持多级目录|全】
ZIP解压缩文件的工具类[支持多级目录|全] 作者:Vashon 网上有很多的加压缩示例代码,但是都只是支持一级目录的操作,如果存在多级目录的话就不行了.本解压缩工具类经过多次检查及重构,最终分享给大 ...