jQuery源码分析随笔之数据缓存

删除回忆录丶 提交于 2020-03-16 20:10:00

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;
        }

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!