jQuery的数据缓存机制对于js Object和DOM node分别存在两种方式:
情况一:对于js Object,数据就存储在Object本身,只不过数据都存储在Object下一个以“jQuery”开头的属性之下
例如:
var obj = {};
$.data(obj, "username", "scott");
console.log(obj);
此时obj为:
{
jQuery16302287385049276054:{
username: "scott"
}
}
情况二:对于DOM node,数据则存储在jQuery.cache之中node对应的id号之下
例如:
var elem = document.createElement("div");
$.data(elem, "password", "tiger");console.log(elem[$.expando]);
console.log($.cache);
输出为:
1
{1:{password:"tiger"}}
这个例子中node对应的id为1,存储在其自身的$.expando属性之下,此id即对应$.cache中存储器数据位置的id,即这样建立起的对应关系
这里需要说明的是,$.expando的值即是以"jQuery"开头后面一串数字的字符串,例如前面的"jQuery16302287385049276054",其作用是表示jQuery文件,因为页面中每个jQuery文件(如果有多个文件的话)都有不同的expando值
关于在DOM node情况下,其id的产生,在jQuery中维持了一个叫"uuid"的值,每次调用时"uuid"都加1
ps:当参数pvt为true时,表明此次存储的是jQuery内部数据,而不是用户自定义数据,对于js Object和DOM node其存储位置:
js Object:
{
jQuery16302287385049276054:{
jQuery16302287385049276054:{username: "scott"}
}
}
DOM node:
{
1:{
jQuery16302287385049276054:{password: "tiger"}
}
}
以下是源码及注释
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, ret,
// jQuery的id
internalKey = jQuery.expando,
getByName = typeof name === "string",
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
// 在IE6-7中,对DOM-JS之间的引用的垃圾回收机制存在问题,主要是因其对DOM(其实现是COM并不是javascript实现的而是C++)采用了引用计数回收策略
// 这有可能产生循环引用导致内存泄露,所以学要对DOM节点和JS对象分开处理
isNode = elem.nodeType,
// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
// 只有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值,若是DOM节点其id的值即节点自身的jQuery.expando属性的值,若是object其id就是jQuery.expando(若id存在的话)
id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
// 当取数据时,情况一:若id为空表示没有任何数据,直接返回;情况二:id不为空,但是要取的是内部数据,但是存放内部数据额的对象不存在,直接返回
if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) {
return;
}
if ( !id ) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
// 若是DOM节点,则给其分配一个唯一的id值,否则将id设为jQuery.expando
if ( isNode ) {
elem[ jQuery.expando ] = id = ++jQuery.uuid;
} else {
id = jQuery.expando;
}
}
if ( !cache[ id ] ) {
cache[ id ] = {};
// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
// metadata on plain JS objects when the object is serialized using
// JSON.stringify
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
if ( typeof name === "object" || typeof name === "function" ) {
// 若pvt为true,说明这是要存储jQuery内部数据而不是用户定义数据,为了区别jQuery内部数据与用户自定义数据,于是将内部数据存储在internalKey属性对应的对象中
if ( pvt ) {
cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
} else {
cache[ id ] = jQuery.extend(cache[ id ], name);
}
}
thisCache = cache[ id ];
// Internal jQuery data is stored in a separate object inside the object's data
// cache in order to avoid key collisions between internal data and user-defined
// data
// 若pvt为true,说明这是要存储jQuery内部数据而不是用户定义数据,为了区别jQuery内部数据与用户自定义数据,于是将内部数据存储在internalKey属性对应的对象中
if ( pvt ) {
if ( !thisCache[ internalKey ] ) {
thisCache[ internalKey ] = {};
}
thisCache = thisCache[ internalKey ];
}
//存储数据
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
// not attempt to inspect the internal events object using jQuery.data, as this
// internal data object is undocumented and subject to change.
if ( name === "events" && !thisCache[name] ) {
return thisCache[ internalKey ] && thisCache[ internalKey ].events;
}
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
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;
}
来源:https://www.cnblogs.com/dreamland/archive/2013/05/30/3107643.html