乌托
data方法的主要流程:
确定是否有参数传入->
1.没有参数-> 使用jquery的静态方法 jQuery.data(elem);(elem是调用data()的对象)->返回elem对象的所有cache缓存,如果elem是dom类型且属性没有解析过,则解析elem的属性是否有data-开头的属性,如果有通过dataAttr(elem, name, data[name]);(data[name]的作用:查看是否添加过这个属性,如果有dataAttr直接返回data[name],减少不必要的操作) 得到以data-开头属性对应的值并进行类型转换,之后添加键值对到elem对象的cache缓存;->调用对象elem的缓存
2.有一个参数->
(1). 如果参数是对象 ->调用jquery的静态方法jQuery.data( this, key ); //添加到调用对象的缓存
(2). 非对象类型的参数-> 调用dataAttr(elem, key, jQuery.data( elem, key ) )// jQuery.data( elem, key ) 如果有值代表有缓存,dataAttr会返回这个缓存,如果没有值dataAttr查看调用对象elem的dom属性是否有data-开头的属性,有就返回,没有返回undefined;->返回key的值
3.有一个以上的参数->jquery的静态方法调用 jQuery.data( this, key, value );
源代码解析:
1.原生方法 data()
data: function( key, value ) {
var i, name, data,
elem = this[0], //调用对象
// attrs =elem? elem.attributes : undefined;
attrs = elem && elem.attributes;
//如果没有参数
if ( key === undefined ) {
//如果有elem对象
if ( this.length ) {
// 返回elem对象的所有cache缓存
data = jQuery.data( elem );
//如果是 DOM 元素 && 如果elem对象没有parsedAttrs属性执行html属性data—解析
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
i = attrs.length; // 返回elem对象属性的数量
while ( i-- ) {
if ( attrs[ i ] ) { //attrs[i] elem对象属性的第i个键值对
name = attrs[ i ].name; //elem对象属性名
//是否存在data-开头的属性
if ( name.indexOf( "data-" ) === 0 ) {
//取到data-后面的属性名,进行一次驼峰命名转换
name = jQuery.camelCase( name.slice(5) );
//通过 dataAttr 解析 elem 元素身上的 html 标签 "data-" 的值
dataAttr( elem, name, data[ name ] );
}
}
}
//给elem对象添加parsedAttrs属性,预防多次解析,浪费性能
jQuery._data( elem, "parsedAttrs", true );
}
}
return data;
}
// 如果key是对象
if ( typeof key === "object" ) {
//每个调用对象执行一次
return this.each(function() {
//在缓存中储存key对象
jQuery.data( this, key );
});
}
//如果参数大于1
return arguments.length > 1 ?
//每个调用对象执行一次
this.each(function() {
//在缓存中储存键值对
jQuery.data( this, key, value );
}) :
//如果参数只有一个&&有调用对象,Query.data( elem, key ) 如果有值代表有缓存,dataAttr会返回这个缓存,如果没有值dataAttr查看调用对象elem的dom属性是否有data-开头的属性,有就返回,没有返回undefined;
elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
}
2.静态方法 $.data()
data: function( elem, name, data ) {
return internalData( elem, name, data );
}
3.函数 internalData()
function internalData( elem, name, data, pvt ) {
//检查 elem 元素是否可以设置数据
if ( !jQuery.acceptData( elem ) ) {
return;
}
var ret, thisCache,
// 产生jQuery键值随机数 类似于: "11020056177454302087426"
// jQuery.expando = (core_version + Math.random()).replace(/D/g, "");
// (core_version + Math.random()) 产生一串随机字符串 "1.10.20.6013481540139765"
// replace(/D/g, "") 去掉非数字
internalKey = jQuery.expando
//确定是否是dom元素
isNode = elem.nodeType,
//是dom元素,取到缓存对象 。如果是 JS 对象,则直接将数据保存在这个对象上,
cache = isNode ? jQuery.cache : elem,
//elem的internalKey 属性对应全局缓存中的位置
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
// 如果是读取数据,且没有数据,则返回
if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
return;
}
if ( !id ) {
if ( isNode ) {
// 对于 DOM 结点,jQuery.uuid 会自加 1,并附加到 DOM 元素上
id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
} else {
id = internalKey;
}
}
if ( !cache[ id ] ) {
// 对于 DOM 如果数据缓存对象不存在,则初始化为空对象 {}
// 对于 JS 对象,设置方法 toJSON 为空函数,以避免在执行 JSON.stringify() 时暴露缓存数据
// 如果一个对象定义了方法 toJSON(), JSON.stringify() 在序列化该对象时会调用这个方法来生成该对象的 JSON 元素
cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
}
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 );
}
}
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.
if ( !pvt ) {
if ( !thisCache.data ) {
thisCache.data = {};
}
thisCache = thisCache.data;
}
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
if ( typeof name === "string" ) {
// 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;
}
4.
整个流程中多次使用:
jquery静态方法: jQuery.data(elem,key,data) , 函数: dataAttr(elem,key,data)
jQuery.data源代码:
data: function( elem, name, data ) {
return internalData( elem, name, data );
},