博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery1.9.1--data缓存对象源码分析
阅读量:4350 次
发布时间:2019-06-07

本文共 12836 字,大约阅读时间需要 42 分钟。

1 // 匹配结尾是否有“{...}”或"[...]"  2     var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,  3         // 匹配大写字母  4         rmultiDash = /([A-Z])/g;  5   6     /**  7      * 内部用来设置/获取元素或对象的缓存方法  8      *  9      * @param elem DOM元素或者JS对象 10      * @param name 缓存的标识符key 11      * @param data 缓存数据 12      * @param {Boolean} pvt 当为true时表示是私有性的,jq内部使用的 13      */ 14  15     function internalData(elem, name, data, pvt /* Internal Use Only */ ) { 16         // 判断该对象能不能绑定数据 17         if (!jQuery.acceptData(elem)) { 18             return; 19         } 20  21         var thisCache, ret, 22             // expando是jQuery生成的随机ID 23             internalKey = jQuery.expando, 24             getByName = typeof name === 'string', 25             // 我们不得不分别处理DOM元素和js对象, 26             // 因为ie6/7的垃圾回收不能正确处理对DOM元素的对象引用 27             isNode = elem.nodeType, 28             // 只有DOM元素才需要全局jQuery.cache对象。 29             // js对象数据直接指向该对象,垃圾回收可以自动处理 30             cache = isNode ? jQuery.cache : elem, 31             // 1. 如果是dom元素,返回dom元素通过expando对应的id(值可能为undefined) 32             // 2. 如果是普通js对象,分两种情况: 33             //    2.1 如果js对象存在通过expando对应的值,即代表有缓存数据,则立即返回expando作为id 34             //    2.2 如果没有对应值,则代表没有缓存数据,此时返回undefined 35             // 也就是说如果id不为空,那么肯定是有存储数据过的 36             id = isNode ? elem[internalKey] : elem[internalKey] && internalKey; 37  38         // 当一个对象没有data的时候返回,避免多余工作 39         if ((!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined) { 40             return; 41         } 42  43         // 如果没有ID 44         if (!id) { 45             // 如果是DOM元素,给该节点绑定一个属性ID 46             if (isNode) { 47                 elem[internalKey] = id = core_deletedIds.pop() || jQuery.guid++; 48             } else { 49                 // 否则是对象则通过expando创建一个唯一ID 50                 id = internalKey; 51             } 52         } 53  54         // 如果cache对象没有指定id属性 55         if (!cache[id]) { 56             cache[id] = {}; 57  58             // 当为JS对象时,为了避免被JSON.stringify序列化 59             // 这里将toJSON方法设为空方法,这样就会返回空值 60             if (!isNode) { 61                 cache[id].toJSON = jQuery.noop; 62             } 63         } 64  65  66         // 如果name是对象或函数,当存在pvt将name浅复制给cache[id], 67         // 否则浅复制给cache[id].data 68         if (typeof name === 'object' || typeof name === 'function') { 69             if (pvt) { 70                 cache[id] = jQuery.extend(cache[id], name); 71             } else { 72                 cache[id].data = jQuery.extend(cache[id].data, name); 73             } 74         } 75  76         thisCache = cache[id]; 77  78         // 为了防止系统内部数据和用户自定义数据的key发生冲突,才将用户数据包在thisCache.data中, 79         // pvt的意思是保持私有性,非私有性时对外提供data属性对象 80         // 系统内部数据就是thisCache中 81         if (!pvt) { 82             if (!thisCache.data) { 83                 thisCache.data = {}; 84             } 85  86             // 只对外开放thisCache.data属性值 87             thisCache = thisCache.data; 88         } 89  90         // 如果data不为undefined,将data赋值给thisCache的通过驼峰式的name属性 91         if (data !== undefined) { 92             thisCache[jQuery.camelCase(name)] = data; 93         } 94  95         // 如果name是字符串 96         if (getByName) { 97             // 尝试获取thisCache的属性data 98             ret = thisCache[name]; 99 100             // 如果ret为null或undefined,则尝试获取驼峰式的name属性data值101             if (ret == null) {102                 ret = thisCache[jQuery.camelCase(name)];103             }104         } else {105             // 否则name为非字符串时,ret指向thisCache106             ret = thisCache;107         }108 109         return ret;110     }111 112     /**113      * 删除对应的缓存数据114      *115      * @param elem116      * @param name117      * @param pvt118      */119 120     function internalRemoveData(elem, name, pvt) {121         if (!jQuery.acceptData(elem)) {122             return;123         }124 125         var i, l, thisCache,126             isNode = elem.nodeType,127             cache = isNode ? jQuery.cache : elem,128             id = isNode ? elem[jQuery.expando] : jQuery.expando;129 130         // 如果没有缓存对象,返回131         if (!cache[id]) {132             return;133         }134 135         if (name) {136             thisCache = pvt ? cache[id] : cache[id].data;137 138             if (thisCache) {139                 // 支持单个的key140                 // 数组,多个key,如:[key1, key2, key3, ...]141                 // 字符串,多个key,用空格隔开,如:'key1 key2 key3 ...'142 143                 // 如果name不是数组类型,将name转换为数组类型144                 if (!jQuery.isArray(name)) {145                     // 如果name是thisCache的一个属性key146                     if (name in thisCache) {147                         // 用数组保存148                         name = [name];149                     } else {150                         // 将name驼峰化151                         name = jQuery.camelCase(name);152                         // 此时若name是thisCache的一个属性key153                         if (name in thisCache) {154                             // 同样转换成数组155                             name = [name];156                         } else {157                             // 否则name是个多个空白分隔的字符串158                             name = name.split(' ');159                         }160                     }161                     // 如果是数组,将name数组各项驼峰化后追加到name数组里162                 } else {163                     name = name.concat(jQuery.map(name, jQuery.camelCase));164                 }165 166                 // 遍历删除name数组里的各项key属性167                 for (i = 0, l = name.length; i < l; i++) {168                     delete thisCache[name[i]];169                 }170 171                 // 如果pvt为true,检查thisCache是否为空的数据对象,如果不是直接退出函数172                 // 如果pvt为false,判断thisCache是否为空对象,如果不是也是退出173                 // 这里考虑到用户自定义或者其他私有受保护的属性174                 if (!(pvt ? isEmptyDataObject : jQuery.isEmptyObject)(thisCache)) {175                     return;176                 }177             }178         }179 180         // 如果pvt为false,即非私有性181         // 删除data属性值182         if (!pvt) {183             delete cache[id].data;184 185             // 同理,这时cache[id]还存在其他属性,退出186             if (!isEmptyDataObject(cache[id])) {187                 return;188             }189         }190 191         // 如果是DOM元素,清除绑定在elem上的所有数据192         if (isNode) {193             jQuery.cleanData([elem], true);194         } else if (jQuery.support.deleteExpando || cache != cache.window) {195             // 如果支持删除绑定在对象上的expando属性或者cache非window对象196             // 只用delete就可以删除了197             delete cache[id];198         } else {199             // 其他情况就将属性设为null来清空缓存200             cache[id] = null;201         }202     }203 204     jQuery.extend({205         // 当是DOM元素的时候,使用$.cache来缓存数据206         cache: {},207         // 生成expando字符串208         expando: 'jQuery' + (core_version + Math.random()).replace(/\D/g, ''),209         // 以下情况不需要缓存210         noData: {211             'embed': true,212             'object': 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000',213             'applet': true214         },215         // 判断是否已有缓存数据216         hasData: function(elem) {217             elem = elem.nodeType ? jQuery.cache[elem[jQuery.expando]] : elem[jQuery.expando];218             return !!elem && !isEmptyDataObject(elem);219         },220         // 适配器模式221         data: function(elem, name, data) {222             return internalData(elem, name, data);223         },224         removeData: function(elem, name) {225             return internalRemoveData(elem, name);226         },227         // 私有方法228         _data: function(elem, name, data) {229             return internalData(elem, name, data, true);230         },231         _removeData: function(elem, name) {232             return internalRemoveData(elem, name, true);233         },234         // 判断元素或对象是否可以缓存235         acceptData: function(elem) {236             if (elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9) {237                 return false;238             }239 240             var noData = elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()];241 242             return !noData || noData !== true && elem.getAttribute('classid') === noData;243         }244     });245 246     jQuery.fn.extend({247         data: function(key, value) {248             var attrs, name,249                 elem = this[0],250                 i = 0,251                 data = null;252 253             // 如果key为undefined,说明key和value都为空,获取缓存data254             if (key === undefined) {255                 // 如果有DOM元素256                 if (this.length) {257                     // 获取以前保存在elem的data258                     data = jQuery.data(elem);259 260                     // 对于元素节点而言,数据可以来自两个地方:261                     // 1. jQuery.cache缓存中,之前手动存进去的,如:$dom.data('data1', value1);262                     // 2. 来自html标签的以data-开头的属性,之后该属性的数据也会被存储到jQuery.cache缓存中263 264                     // 如果元素节点的jQuery.cache['parsedAttrs']的值为null | false | undefined265                     // 说明elem的属性节点没有被解析过,下面就进行解析266                     if (elem.nodeType === 1 && !jQuery._data(elem, 'parsedAttrs')) {267                         // 获得elem的属性列表268                         attrs = elem.attributes;269                         for (; i < attrs.length; i++) {270                             // 该属性名称271                             name = attrs[i].name;272 273                             // 如果name有"data-"字符274                             if (!name.indexOf('data-')) {275                                 // 将name驼峰化:"dataCustom"276                                 name = jQuery.camelCase(name.slice(5));277 278                                 // 如果没有对应的缓存,就将html5的“data-”值(转换后)设置为相应的缓存值279                                 dataAttr(elem, name, data[name]);280                             }281                         }282                         // 给缓存对象添加私有缓存,并把缓存值设置为true283                         // 用来标记已经解析过属性284                         jQuery._data(elem, 'parseAttrs', true);285                     }286                 }287 288                 return data;289             }290 291             // 如果key是对象,直接将其拷贝到jQuery.cache.data缓存对象里292             // 用来设置多个值的情况293             if (typeof key === 'object') {294                 return this.each(function() {295                     jQuery.data(this, key);296                 });297             }298 299             // 为每个元素执行函数后返回原始的元素集(this)300             return jQuery.access(this, function(value) {301                 if (value === undefined) {302                     // 如果value未定义并且在jQuery.cache缓存中没有找到相应key的缓存,303                     // 然后再试图查看HTML5标签的“data-”属性是否被解析过了304                     return elem ? dataAttr(elem, key, jQuery.data(elem, key)) : null;305                 }306             }, null, value, arguments.length > 1, null, true);307         },308         removeData: function(key) {309             return this.each(function() {310                 jQuery.removeData(this, key);311             });312         }313     });314 315     // 处理元素节点中使用HTML5的“data-test”属性,并将其转换到相应的类型存储到jQuery.cache对象中316 317     function dataAttr(elem, key, data) {318         // 如果data为空且elem是元素节点,那么将HTML5的data-属性值转换为相应的类型319         if (data === undefined && elem.nodeType === 1) {320             // 反驼峰化321             var name = 'data-' + key.replace(rmultiDash, '-$1').toLowerCase();322 323             // 获取data字符串属性值324             data = elem.getAttribute(name);325 326             if (typeof data === 'string') {327                 try {328                     // 布尔型329                     data = data === 'true' ? true :330                         data === 'false' ? false :331                     // null332                     data === 'null' ? null :333                     // +data只会将数字字符转换成数字,再加上""则会转换回字符串334                     // 这里是测试是否为数字335                     +data + '' === data ? +data :336                     // 数组或对象,并转换337                     rbrace.test(data) ? jQuery.parseJSON(data) :338                     // 其他类型339                     data;340                 } catch (e) {}341 342                 // 将格式化的数据存在jQuery.cache缓存。343                 jQuery.data(elem, key, data);344             } else {345                 // 如果该属性不存在,此时data为null,将其转换为undefined346                 data = undefined;347             }348         }349 350         // 返回data-属性值(转换后)的类型351         return data;352     }353 354     // 检查缓存对象的数据是否为空355 356     function isEmptyDataObject(obj) {357         var name;358         for (name in obj) {359             // 如果公共data为空,那么私有对象也为空360             if (name === 'data' && jQuery.isEmptyObject(obj[name])) {361                 continue;362             }363             if (name !== 'toJSON') {364                 return false;365             }366         }367 368         return true;369     }

 

转载于:https://www.cnblogs.com/webFrontDev/archive/2013/05/29/3106894.html

你可能感兴趣的文章
POJ 3267 The Cow Lexicon(动态规划)
查看>>
tomcat 7服务器跨域问题解决
查看>>
Jenkins安装配置
查看>>
一、 kettle开发、上线常见问题以及防错规范步骤
查看>>
eclipse没有server选项
查看>>
CRC码计算及校验原理的最通俗诠释
查看>>
jquery扩展 $.fn
查看>>
机器分配
查看>>
Windows下安装Redis
查看>>
winform非常实用的程序退出方法!!!!!(转自博客园)
查看>>
centos安装vim
查看>>
linux工作调度(计划任务)
查看>>
NIO:与 Buffer 一起使用 Channel
查看>>
Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析
查看>>
MFC接收ShellExecute多个参数
查看>>
volatile和synchronized的区别
查看>>
类中的静态函数和非静态函数的区别
查看>>
windows 下安装Apache
查看>>
Fedora14 mount出现错误时解决办法【亲测有效】
查看>>
ruby实现生产者和消费者
查看>>