咱們常常使用隱藏控件或者是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獲取某個對象上附加的全部屬性。