// Unique for each copy of jQuery on the page // Non-digits removed to match rinlinejQuery expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
.... data: function( elem, name, data, pvt /* Internal Use Only */ ) { // 是否可以附加数据,不可以则直接返回 if ( !jQuery.acceptData( elem ) ) { return; }
var privateCache, thisCache, ret, //jQuery.expando这是一个唯一的字符串,是这介jquery对象产生的时候就生成了。 internalKey = jQuery.expando, getByName = typeof name === "string",
// 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 = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, isEvents = name === "events";
// 避免做更多的不必要工作,当尝试在一个没有任何数据的对象上获取数据时 // 对象没有任何数据,直接返回 if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { return; } // id不存在的话就生成一个 if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { // 如果是DOM元素则在元素上产生唯一的ID 并且以jQuery.expando //为属性值为id保存在elem元素上,以便以后再根据jQuery.expando来查找ID。 elem[ internalKey ] = id = ++jQuery.uuid; } else { // JS对象则直接使用jQuery.expando,既然是直接附加到对象上,又何必要id呢? // 避免与其他属性冲突! id = internalKey; } }
//// 当我们试着访问一个键是否含有值的时候,如果不存在jQuery.cache[id]值, // 初始化jQuery.cache[id]值 为一个空对象{} if ( !cache[ id ] ) { cache[ id ] = {};
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 // data是接收对象和函数,浅拷贝 if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ] = jQuery.extend( cache[ id ], name ); } else { cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } / 存储对象,存放了所有数据的映射对象 privateCache = thisCache = cache[ id ];
// jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. // jQuery内部数据存在一个独立的对象(thisCache.data==thisCache[ internalKey ]) //上,为了避免内部数据和用户定义数据冲突 if ( !pvt ) { // 存放私有数据的对象不存在,则创建一个{} if ( !thisCache.data ) { thisCache.data = {}; } // 使用私有数据对象替换thisCache thisCache = thisCache.data; } // 如果data不是undefined,表示传入了data参数,则存储data到name属性上 if ( data !== undefined ) { // jQuery.camelCase( name )作用是如果传入的是object/function,不做转换, //只有传入的name是字符串才会转换。所以最终保存下来的是key/value对; thisCache[ jQuery.camelCase( name ) ] = data; }
if ( args ) { if ( length === undefined ) { for ( name in object ) if ( callback.apply( object[ name ], args ) === false ) break; } else for ( ; i 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 value = object[++i] ){} }
return object; }
现在我们关注下 for ( var value = object[0]; i 得到遍历整个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代码:
代码如下:
jQuery.fn.extend({ data: function( key, value ) { var parts, part, attr, name, l, elem = this[0], i = 0, data = null;
// Gets all values if ( key === undefined ) { .....//处理没有Key的情况,这里不是我们要讨论的