咱们常常使用隐藏控件或者是js全局变量来临时存储数据,全局变量容易致使命名污染,隐藏控件致使常常读写dom浪费性能。jQuery提供了本身的数据缓存方案,可以达到和隐藏控件、全局变量相同的效果,可是jQuery实现方式更优雅。为了更好地使用jQuery数据缓存方案,咱们须要掌握$.data()、$.cache、$.expando、$.hasData()、$.removeData()。javascript
$.hasData()用来判断某个对象是否有附加的属性,能够给任何JavaScript对象和HTMLElement对象附加属性。$.data()用来读取或者修改属性值。$.removeData()用来删除已经添加的属性,这是为了释放内存,避免过多无用属性浪费内存。html
- var myObj = {};
- console.log(jQuery.hasData($("#a")));
-
- $.data(myObj, 'name', 'aty');
- console.log(jQuery.hasData(myObj));
-
- console.log($.data(myObj, 'name'));
-
- $.removeData(myObj, 'name');
- console.log($.data(myObj, 'name'));
-
- console.log(jQuery.hasData(myObj));
给HTMLElement对象添加属性,使用方式跟为普通js对象添加属性如出一辙。java
- <div id="content"></div>
- <script>
- var el = document.getElementById('content');
- $.data(el, 'name', 'aty');
- console.log($.data(el, 'name')); // aty
- </script>
能够看到使用jQuery数据缓存的API是很容易的,如今咱们要大体看下jQuery是如何实现缓存方案。为普通JS对象提供缓存时,jquery直接将数据保存在原始的JS对象上。此时会偷偷的给JS对象添加个属性(相似于jQuery16101803968874529044),属性值也是一个对象。jquery
- var myObj = {};
- $.data(myObj, 'name', 'aty');
- console.log(myObj);
- console.log($.expando);
咱们能够看到myObj结构发生了变化:jquery给普通对象偷偷添加的属性名称其实就是$.expando。缓存

jQuery.expando是一个字符串,使用Math.random生成,去掉了非数字字符。它做为HTMLElement或JS对象的属性名。页面引入jQuery框架的时候,会随机生成一个字符串。框架
- expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
如今咱们知道了jQuery如何给普通对象添加属性,以及expando的含义,那么咱们就能够经过下面的代码获取添加的属性。dom
- var hisObj = {};
- $.data(hisObj, 'name', 'him');
- console.log(hisObj[jQuery.expando].data.name);
为HTMLElement提供缓存时,却不会直接保存在HTMLElement上。而是保存在jQuery.cache这个全局对象上。此时先给HTMLElement添加属性(jQuery.expando),属性值为数字(1,2,3递增)。即只将一些数字保存在了HTMLElement上,不会直接将数据置入。这是由于IE老版本中可能会存在内存泄露危险。而HTMLElement如何与jQuery.cache创建联系呢? 仍是id。刚刚提到属性值数字就是id。性能
- <div id="a"></div>
- <script>
- var dom = document.getElementById("a");
- $.data(dom, 'name', 'aty');
- console.log(dom[jQuery.expando]); // 1
- console.log(jQuery.cache); // {1 : {data:{name:'aty'}}}
- </script>

知道了jQuery如何为dom对象添加属性,咱们就能够经过下面的代码获取属性。spa
- console.log(jQuery.cache[dom[jQuery.expando]].data.name);
如今咱们看下DOM对象和jQuery封装后的对象有什么区别。.net
- var dom = document.getElementById("a");
- $.data(dom, 'name', 'aty');
- console.log(jQuery.hasData(dom));
- console.log($.data(document.getElementById("a"), 'name'));
- console.log($.data($("#a")[0], 'name'));
-
- var $dom = $("#a");
- $.data($dom, 'age', '25');
- console.log(jQuery.hasData($dom));
- console.log($.data($dom, 'age'));
- console.log($.data($("#a"), 'age'));

这是由于本质区别在于:原始的DOM对象会被jQuery特殊对待,而jQuery包装后的对象与普通JS对象无异。经过jQuery选择器每次获取的对象并非同一个对象。
- var $dom = $("#a");
- $.data($dom, 'age', '25');
-
- console.log( document.getElementById("a") === document.getElementById("a"));
- console.log( document.getElementById("a") === $("#a")[0]);
- console.log($("#a") === $("#a"));
-
- console.log($dom[jQuery.expando].data.age);
最后再提一下,可使用$.data获取某个对象上附加的全部属性。