jQuery对象数据缓存Cache原理及jQuery.data详解

网上有很多教你怎么使用jQuery.data(..)来实现数据缓存,但有两个用户经常使用的data([key],[value])和jQuery.data(element,[key],[value])几乎没有什么文章说清楚它们两的区别,所以我用到了,研究下分享给大家。
$("").data([key],[value])与jQuery.data(element,[key],[value])的区别
这两个函数都是用来在元素上存放数据也就平时所说的数据缓存,都返回jQuery对象,当时我分别在使用它俩的时候真的吓我一跳,区别可大了,真是不用不知道,一用吓一跳。看例子先吧,后再根据源代码分析。

Js代码: 
  1. "test2" οnclick="test()">test2
  
  •           "abc3" οnclick="test()">test3
  •   
  •           "test" οnclick="test()">test
  •   
  •           "ttt">aaaa

      
  •       
  •     看了上面的例子是不是发现data([key],[value])与jQuery.data(element,[key],[value])两个根本就不一样了对吧?它们之间到底有没有关系呢。怎么data([key],[value])会覆盖前面key相同的值呢?
    而jQuery.data(element,[key],[value])只要是绑定到不同的对象上都不会造成覆盖。是这样吗?那来研究下它们的源代码吧。
    先看jQuery.data(element,[key],[value])源代码。

    Js代码:  
    1. jQuery.extend({  
    2.     cache: {},  
    3.   
    4.     // Please use with caution  
    5.     uuid: 0,  
    6.   
    7.     // Unique for each copy of jQuery on the page  
    8.     // Non-digits removed to match rinlinejQuery  
    9.     expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),  
    10.   
    11.     ....  
    12.     data: function( elem, name, data, pvt /* Internal Use Only */ ) {  
    13.     // 是否可以附加数据,不可以则直接返回  
    14.         if ( !jQuery.acceptData( elem ) ) {  
    15.             return;  
    16.         }  
    17.   
    18.         var privateCache, thisCache, ret,  
    19.             //jQuery.expando这是一个唯一的字符串,是这介jquery对象产生的时候就生成了。  
    20.             internalKey = jQuery.expando,  
    21.             getByName = typeof name === "string",  
    22.   
    23.             // 必须区分处理DOM元素和JS对象,因为IE6-7不能垃圾回收对象跨DOM对象和JS对象进行的引用属性  
    24.             isNode = elem.nodeType,  
    25.   
    26.              // 如果是DOM元素,则使用全局的jQuery.cache   
    27.              // 如果是JS对象,则直接附加到对象上  
    28.             cache = isNode ? jQuery.cache : elem,  
    29.   
    30.             // Only defining an ID for JS objects if its cache already exists allows  
    31.             // the code to shortcut on the same path as a DOM node with no cache  
    32.             id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,  
    33.             isEvents = name === "events";  
    34.   
    35.          // 避免做更多的不必要工作,当尝试在一个没有任何数据的对象上获取数据时  
    36.        // 对象没有任何数据,直接返回  
    37.         if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {  
    38.             return;  
    39.         }  
    40.         // id不存在的话就生成一个  
    41.         if ( !id ) {  
    42.             // Only DOM nodes need a new unique ID for each element since their data  
    43.             // ends up in the global cache  
    44.             if ( isNode ) {  
    45.              // 如果是DOM元素则在元素上产生唯一的ID 并且以jQuery.expando  
    46.              //为属性值为id保存在elem元素上,以便以后再根据jQuery.expando来查找ID。  
    47.                 elem[ internalKey ] = id = ++jQuery.uuid;  
    48.             } else {  
    49.             // JS对象则直接使用jQuery.expando,既然是直接附加到对象上,又何必要id呢?  
    50.               // 避免与其他属性冲突!  
    51.                 id = internalKey;  
    52.             }  
    53.         }  
    54.   
    55.         //// 当我们试着访问一个键是否含有值的时候,如果不存在jQuery.cache[id]值,  
    56.         // 初始化jQuery.cache[id]值 为一个空对象{}  
    57.         if ( !cache[ id ] ) {  
    58.          cache[ id ] = {};  
    59.    
    60.             if ( !isNode ) {  
    61.                 cache[ id ].toJSON = jQuery.noop;  
    62.             }  
    63.         }  
    64.   
    65.         // An object can be passed to jQuery.data instead of a key/value pair; this gets  
    66.         // shallow copied over onto the existing cache  
    67.         // 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.         privateCache = thisCache = cache[ id ];  
    77.   
    78.         // jQuery data() is stored in a separate object inside the object's internal data  
    79.         // cache in order to avoid key collisions between internal data and user-defined  
    80.         // data.  
    81.         // jQuery内部数据存在一个独立的对象(thisCache.data==thisCache[ internalKey ])  
    82.           //上,为了避免内部数据和用户定义数据冲突  
    83.         if ( !pvt ) {  
    84.               // 存放私有数据的对象不存在,则创建一个{}  
    85.             if ( !thisCache.data ) {  
    86.                 thisCache.data = {};  
    87.             }  
    88.              // 使用私有数据对象替换thisCache  
    89.             thisCache = thisCache.data;  
    90.         }  
    91.        // 如果data不是undefined,表示传入了data参数,则存储data到name属性上  
    92.         if ( data !== undefined ) {  
    93.         // jQuery.camelCase( name )作用是如果传入的是object/function,不做转换,  
    94.         //只有传入的name是字符串才会转换。所以最终保存下来的是key/value对;  
    95.             thisCache[ jQuery.camelCase( name ) ] = data;  
    96.         }  
    97.   
    98.         //从这以后下面的代码都是处理data: function( elem, name)data为空,求返回值data的情况了。  
    99.   
    100.         if ( isEvents && !thisCache[ name ] ) {  
    101.             return privateCache.events;  
    102.         }  
    103.   
    104.        // 如果name是字符串,则返回data 
    105.        // 如果不是,则返回整个存储对象  
    106.         if ( getByName ) {  
    107.   
    108.             // First Try to find as-is property data  
    109.             ret = thisCache[ name ];  
    110.   
    111.             // Test for null|undefined property data  
    112.             if ( ret == null ) {  
    113.   
    114.                 // Try to find the camelCased property  
    115.                 ret = thisCache[ jQuery.camelCase( name ) ];  
    116.             }  
    117.         } else {  
    118.             ret = thisCache;  
    119.         }  
    120.   
    121.         return ret;  
    122.     },  
    123.     ............  
    124.     });  

    请看图。

     

     看jQuery.data(element,[key],[value])源代码后可以知道,每一个element都会有自己的一个{key:value}对象保存着数据,所以新建的对象就算有key相同它也不会覆盖原来存在的对象key所对应的value,因为新对象保存是是在另一个{key:value}对象中。

             接下来要分析data([key],[value])源代码使用到了each(callback),在分析它之前先看下each(callback)用法和源代码。

    Js代码: 
    1.     "test2" οnclick="test()">test2
      
  •          "abc3" οnclick="test()">test3
  •   
  •           "test" οnclick="test()">test
  •   
  •           "ttt">aaaa

      
  •       
  •   
  • 现在来看each方法的具体实现如下:  
  • jQuery.fn = jQuery.prototype = {  
  •     each: function( callback, args ) {  
  •        return jQuery.each( this, callback, args );  
  •     }  
  • }  
  •   
  • 可以看到它返回的是全局的each方法,并且将自身jQuery对象做为参数给它,全局的each方法的具体实现如下:  
  • // args 作为内部成员的调用来使用  
  • each: function( object, callback, args ) {  
  •     var name, i = 0, length = object.length;  // 当object为jQuery对象时,length非空  
  •   
  •     if ( args ) {  
  •         if ( length === undefined ) {  
  •             for ( name in object )  
  •                 if ( callback.apply( object[ name ], args ) === false )  
  •                     break;  
  •         } else  
  •             for ( ; i < length; )  
  •                 if ( callback.apply( object[ i++ ], args ) === false )  
  •                     break;    
  •     // 以下是客户端程序进行调用  
  •     } else {  
  •         if ( length === undefined ) {  
  •             for ( name in object )  
  •                 if ( callback.call( object[ name ], name, object[ name ] ) === false )  
  •                     break;  
  •         } else  
  •             // i表示索引值,value表示DOM元素  
  •             for ( var value = object[0];  
  •                 i < length && callback.call( value, i, value ) !== false;   
  •                 value = object[++i] ){}  
  •     }    
  •   
  •     return object;  
  • }  
  •  现在我们关注下 for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} 这句代码;其中object[0]取得jQuery对象中的第一个DOM元素,通过for循环,
    得到遍历整个jQuery对象中对应的每个DOM元素,通过callback.call( value,i,value); 将callback的this对象指向value对象,并且传递两个参数,i表示索引值,value表示DOM元素;其中callback是类似于 function(index, elem) { } 的方法。所以就得到 $("").each(function(index, elem){ }); 

     再来看看data([key],[value])的源代码

    Js代码:  
    1. jQuery.fn.extend({  
    2.     data: function( key, value ) {  
    3.         var parts, part, attr, name, l,  
    4.             elem = this[0],  
    5.             i = 0,  
    6.             data = null;  
    7.   
    8.         // Gets all values  
    9.         if ( key === undefined ) {  
    10.             .....//处理没有Key的情况,这里不是我们要讨论的
    11.   
    12.             return data;  
    13.         }  
    14.   
    15.         // Sets multiple values  
    16.         if ( typeof key === "object" ) {  
    17.             return this.each(function() {  
    18.                 jQuery.data( this, key );  
    19.             });  
    20.         }  
    21.   
    22.         parts = key.split( ".", 2 );  
    23.         parts[1] = parts[1] ? "." + parts[1] : "";  
    24.         part = parts[1] + "!";  
    25.   
    26.         return jQuery.access( thisfunction( value ) {  
    27.   
    28.             if ( value === undefined ) {  
    29.                 。。。//这里是没有value时,是索取返回值的情况,这不是我们讨论  
    30.             }  
    31.   
    32.             parts[1] = value;  
    33.   
    34.            //如果我使用用$("div").data("a","aaa")),下面调用each前的this指的是$("div")这返回的对象,  
    35.             this.each(function() {//注意了,这里是以每一个匹配的元素作为上下文来执行一个函数  
    36.                 var self = jQuery( this );  
    37.   
    38.                 self.triggerHandler( "setData" + part, parts );  
    39.   
    40.                 //这里在元素上存放数据,本质还是委托data(element,[key],[value])来做的。  
    41.                  //看前面有分析过了。  
    42.                  //下面data( this, key, value )里的this指的是遍历整个jQuery对象中对应的每个DOM元素  
    43.                  //$("div")它对应页面中一个
      数组。  
    44.             jQuery.data( this, key, value )"background-color: #ffcc00;">;//这名句会被循环多次执行,也就是保存数据。  
    45.                 //这里就是核心一句话。但要清楚看上面了它是在each(functipn(){})中的。  
    46.                 self.triggerHandler( "changeData" + part, parts );  
    47.             });  
    48.         }, null, value, arguments.length > 1, nullfalse );  
    49.     },  
    50. //在元素上移除存放的数据。具体实现如下:   
    51.     removeData: function( key ) {  
    52.         return this.each(function() {  
    53.             jQuery.removeData( this, key );  
    54.         });  
    55.    }  
    56. });  

     

     如果对于data([key],[value])的源代码不是很了解,好吧,我就用一个例子来模仿实现它吧。

    Js代码:  
    1. "test2" οnclick="test()">test2
      
  •           "abc3" οnclick="test()">test3
  •   
  •           "test" οnclick="test()">test
  •   
  •           "ttt">aaaa

      
  •       
  •  现在对data([key],[value])与jQuery.data(element,[key],[value])都有了解了吧,如果还是半懂,再回头多看一遍,耐心地理解一下。其实表面上很不一样。但本质上还是有联系的,现在明白原理后就可以请放心地使用了。jQuery.data(element,[key],[value])只把数据绑定到参数element节点上。data([key],[value])
        如$("div").data("a","aaaa")它是把数据绑定每一个匹配div节点的元素上。
        附加说明下,文中所分析用到的是jquery-1.7.2.js的源代码。下载地址:http://www.software8.co/software/wlbc/3730.html

    你可能感兴趣的:(jQuery对象数据缓存Cache原理及jQuery.data详解)