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