data部分的代码从1381行开始。最开始的几行关键代码:
复制代码 代码如下:
jquery.extend({
// 存储数据的地方,关键实现核心
cache: { },
// 分配id用的seed
uuid: 0,
// 为了区别不同的jquery实例存储的数据,使用前缀+jquery版本号+随机数作为key
expando: jquery + (jquery.fn.jquery + math.random()).replace(/\d/g, ),
// 以下元素没有data:embed和applet(这玩意还活着么),除了flash之外的object。
nodata: {
embed: true,
object: clsid:d27cdb6e-ae6d-11cf-96b8-444553540000,
applet: true
}
});
对外的接口都调用了两个内部函数:jquery.data(elem, name, data, pvt)和jquery.removedata(elem, name, pvt)。而removedata的逻辑与data类似,只是data是加入数据,而removedata使用delete或者设置为null删除数据。
data部分的代码中明确区分了js对象和dom对象的保存,这是为了解决部分浏览器的内存泄漏问题。在低版本ie中,当dom和js对象之间出现循环引用时,gc就无法正确处理。参见understanding and solving internet explorer leak patterns。至于com对象,因为已经限制object元素没有data,就绕过了这个问题。
复制代码 代码如下:
data: function(elem, name, data, pvt) {
// 如果属于nodata中定义的元素
if(!jquery.acceptdata(elem)) {
return;
}
var internalkey = jquery.expando,
getbyname = typeof name === string,
thiscache,
isnode = elem.nodetype,
// dom元素需要保存在cache,js对象直接保存到elem
cache = isnode ? jquery.cache : elem,
// 如果elem的jquery.expando已经有值了,就重用
id = isnode ? elem[jquery.expando] : elem[jquery.expando] && jquery.expando;
// data未定义,说明当前调用是查询数据,但是对象没有任何数据,直接返回
if((!id || (pvt && id && !cache[id][internalkey])) && getbyname && data === undefined) {
return;
}
if(!id) {
if(isnode) {
// 用uuid种子递增分配唯一id,只有dom元素需要。因为需要存在全局cache中
elem[jquery.expando] = id = ++jquery.uuid;
} else {
id = jquery.expando;
}
}
// 清空原来的值
if(!cache[id]) {
cache[id] = {};
if(!isnode) {
cache[id].tojson = jquery.noop;
}
}
// 用extend扩展cache,增加一个属性,用来保存数据
if(typeof name === object || typeof name === function) {
if(pvt) {
cache[id][internalkey] = jquery.expand(cache[id][internalkey], name);
} else {
cache[id] = jquery.extend(cache[id], name);
}
}
thiscache = cahce[id];
// 避免key冲突
if(pvt) {
if(!thiscache[internalkey]) {
thiscahce[internalkey] = {};
}
thiscache = thiscache[internalkey];
}
if(data !== undefined) {
thiscache[jquery.camelcase(name)] = data;
}
return getbyname ? thiscache[jquery.camelcase(name)] : thiscache;
}
removedata: function( elem, name, pvt ) { // 前面部分与data类似 // ... // 部分浏览器不支持在element上进行delete操作,在jquery.support中检查过这个浏览器特性。 // 如果delete失败的话,就先设置成null。 if ( jquery.support.deleteexpando || cache != window ) { delete cache[ id ]; } else { cache[ id ] = null; }
var internalcache = cache[ id ][ internalkey ];
// 如果还有数据,就清空一次再设置,增加性能
if ( internalcache ) {
cache[ id ] = {};
cache[ id ][ internalkey ] = internalcache;
// 已经没有任何数据了,就全部删除
} else if ( isnode ) {
// 如果支持delete,就删除。
// ie使用removeattribute,所以尝试一次。再失败就只能设置为null了。
if ( jquery.support.deleteexpando ) {
delete elem[ jquery.expando ];
} else if ( elem.removeattribute ) {
elem.removeattribute( jquery.expando );
} else {
elem[ jquery.expando ] = null;
}
}
}