jQuery的数据缓存模块
几乎每一个前端库或者框架都有自己的数据缓存模块,而且这个是框架的基础核心模块。所有的应用模块,都会依赖这个数据缓存模块。jQuery也有自己的数据缓存模块,所以把自己学习的心得分享一下。
属性缓存数据
属性缓存数据,就是使用对象的属性或者element元素的attribute来缓存数据。jQuery(1.x)就是利用这个实现的自己的数据缓存模块的。这种方法也叫属性标记法.
element属性attribute标记法
这个写过前端代码的都很熟悉,就是在标签的html上加上自定义属性。
栗子1:
1
2
3
4<!-- element-attribute.html -->
<div id="demo1" customize="defined by me"></div>
<button id="getAttrBtn">getAttr</button>
<button id="setAttrBtn">setAttr</button>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var $ = function (id) {
return document.getElementById(id);
};
var getAttrBtn = $('getAttrBtn');
var setAttrBtn = $('setAttrBtn');
/**
*标签属性标记法
*/
getAttrBtn.onclick = function () {
var demoEle = $('demo1'), value = demoEle.getAttribute('customize');
window.console.log(value);
demoEle.innerHTML = value;
};
setAttrBtn.onclick = function () {
var demoEle = $('demo1'),value;
demoEle.setAttribute('customize', 'changed by element attribute');
value = demoEle.getAttribute('customize');
window.console.log(value);
demoEle.innerHTML = value;
};栗子1就是我们通过element标签来保存一些自己的业务数据。
优点:原生;所有浏览器都支持。
缺点:只能保存字符串,不能保存对象和function,这两种类型。
对象属性标记法
对象属性标记,就很好理解了,就是平时我们给JavaScript对象赋值的操作。
栗子2:
1
2
3
4<!-- element-attribute.html -->
<div id="demo1" customize="defined by me"></div>
<button id="getAttrBtn">getAttr</button>
<button id="setAttrBtn">setAttr</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
*对象属性标记法
*/
getAttrBtn.ondblclick = function () {
var demoEle = $('demo1'), value = demoEle['customize'];
window.console.log(value);
demoEle.innerHTML = value;
};
setAttrBtn.ondblclick = function () {
var demoEle = $('demo1'),value;
demoEle['customize'] = 'changed by object attribute',value = demoEle['customize'];
window.console.log(value);
demoEle.innerHTML = value;
};栗子2就是对象属性标记法,原理就是直接使用浏览器中element(宿主元素)进行数据缓存。
优点:JavaScript全类型的数据都支持。
缺点:
浏览器兼容性问题。
object,applet,embed等对象是不能使用这种方法,进行属性缓存数据,因为他们不是标准的浏览器中的对象,属于扩展内容。
window对象如果使用这种方式,变成了全局变量
内存泄漏:内存泄漏是这种方式的最大威胁。
1
2
3
4
5
6
7// 内存泄漏栗子:
// 最直接的栗子就是demoEle.dep.el的属性指向demoEle
var demoEle = $('demo1');
demoEle.dep = {
el: demoEle
};
// 这样的循环依赖,很难觉察到,所以demoEle.dep和demoEle都得不到回收,造成内存泄漏。
数据缓存模块实现原理
属性缓存数据的两种方法,各有优缺点,但是对象属性缓存数据 已经非常理想了,只要解决一下内存泄漏 这个问题就很实用了。分享一下jQuery的巧妙设计。
jQuery的设计思路:
- 数据统一管理(数据储存在一个对象 中)
- 数据不缓存在具体的element对象属性上,而是在element缓存一个jQueryKey,然后通过jQueryKey存取数据。
jQueryKey:是一个字符串值,不存在循环依赖 解决内存泄漏的问题 。
栗子:
1 | <!-- data-storage.html --> |
1 | function isNumeric(obj) { |
上面的栗子:
Model.cacheKey做element的属性,element[Model.cacheKey]的value值是Model.cache的对象key。
- element[Model.cacheKey]的value值,只是一个字符串所以,完美解决了内存泄漏 问题。
- Model.cache是一个普通的JavaScript对象,所以它可以支持所有的JavaScript的数据类型。解决了在标签的属性上缓存数据,只支持 字符串 的问题。
1 | // 这就是element对应cache中缓存的整个数据对象 |
jQuery数据缓存模块源码
jQuery数据缓存模块的部分源码。
1 | // 下面的就是一些 jQuery 涉及数据存储的操作 |
来一个对应:
- jQuery.expando对应Model.cacheKey
- jQuery.cache对应Model.cache
- jQuery.data对应Model.data
在jQuery.hasData方法内部看到了:
1 | jQuery.cache[elem[jQuery.expando]]; // 取数据 |
1 | Model.cache[indexKey][key]; // Model和jQuery原理是一样的。 |
有了Model这个小栗子,就能更好的理解jQuery的data模块实现原理了;当然jQuery的data模块还有很多其它的兼容性处理,防冲突处理。
HTML5的DataSet API
HTML5加入了一个关于自定义属性的API,很是方便,虽然非现代浏览器不支持,但是你可以使用jQuery,jQuery已经提供了支持。
栗子:
1 | <!-- 自定义属性使用 data-* 开头 --> |
1 | // 原生操作 |
jQuery栗子:
1 | <span data-toggle="dropdown" class="moduleTitle" data-options="234" |
1 | // jQuery操作 |
注意:
jQuery.data访问data-自定义属性是有优先级顺序,先从$.cache中获取,如果没有,才尝试自定义属性获取。
jQuery.data方法只能修改自己缓存内的数据,不会修改data-属性的数据;所以千万不要使用jQuery().attr和jQuery.data混合使用操作data-自定义属性。