// 代码行:4004——4158
function Data() {
// 设定唯一标识
this.expando = jQuery.expando + Data.uid++;
}
Data.uid = 1;
Data.prototype = {
// 建立一个cache
cache: function( owner ) {
// Check if the owner object already has a cache
// 检查所有者对象是否已经拥有缓存
var value = owner[ this.expando ];
// If not, create one
// 如果没有value,则创建一个
if ( !value ) {
value = {};
// We can accept data for non-element nodes in modern browsers,
// but we should not, see #8335.
// Always return an empty object.
// 我们可以在现代浏览器中接受非元素节点的数据,但是我们不应该这么做,总是返回一个空对象。
if ( acceptData( owner ) ) {
// If it is a node unlikely to be stringify-ed or looped over
// use plain assignment
//如果它是一个不太可能被字符串化或循环的节点,使用简单的赋值
// 判断owner是一个合格者后
if ( owner.nodeType ) {
owner[ this.expando ] = value;
// Otherwise secure it in a non-enumerable property
// configurable must be true to allow the property to be
// deleted when data is removed
//否则,将其保护在一个不可枚举的属性中
//可配置的必须为true才能允许属性为true
//删除数据时删除
} else {
Object.defineProperty( owner, this.expando, {
value: value,
configurable: true
} );
}
}
}
return value;
},
// set()用于dom设置key和value
set: function( owner, data, value ) {
var prop,
cache = this.cache( owner );
// Handle: [ owner, key, value ] args
// Always use camelCase key (gh-2257)
if ( typeof data === "string" ) {
cache[ camelCase( data ) ] = value;
// Handle: [ owner, { properties } ] args
// 处理data为这种情况:[ owner, { properties } ]
} else {
// Copy the properties one-by-one to the cache object
// 将属性逐个复制到缓存对象
for ( prop in data ) {
cache[ camelCase( prop ) ] = data[ prop ];
}
}
return cache;
},
get: function( owner, key ) {
return key === undefined ?
this.cache( owner ) :
// Always use camelCase key (gh-2257)
owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
},
// 用来访问,将get、set结合到一起,并对underfined判断
access: function( owner, key, value ) {
// In cases where either:
//
// 1. No key was specified
// 2. A string key was specified, but no value provided
//
// Take the "read" path and allow the get method to determine
// which value to return, respectively either:
//
// 1. The entire cache object
// 2. The data stored at the key
//
//在下列任何一种情况下:1.没有指定密钥。2.指定了字符串键,但没有提供值。选择“read”路径并允许get方法确定,分别返回哪个值:1.整个缓存对象 2.存储在键上的数据
// 如果key是undefined或key是字符串、data是undefined说明实在读取数据
if ( key === undefined ||
( ( key && typeof key === "string" ) && value === undefined ) ) {
return this.get( owner, key );
}
// When the key is not a string, or both a key and value
// are specified, set or extend (existing objects) with either:
//
// 1. An object of properties
// 2. A key and value
//
//当键不是字符串,或者键和值都不是时。指定、设置或扩展(现有对象)时,1.属性的对象。2.键和值
this.set( owner, key, value );
// Since the "set" path can have two possible entry points
// return the expected data based on which path was taken[*]
// 因为“set”路径可以有两个可能的入口点
// 返回所选择路径的期望数据[*]
return value !== undefined ? value : key;
},
// 用于移除cache
remove: function( owner, key ) {
var i,
// 变量cache指向存储数据得对象,对于DOM元素,数据存储在全局缓存对象jQuery.cache中,对于JavaScript对象,数据则直接存储在JavaScript对象上。
cache = owner[ this.expando ];
// 如果数据缓存对象cache不存在,则直接返回。
if ( cache === undefined ) {
return;
}
// 如果key存在,即有待移除得选项
if ( key !== undefined ) {
// Support array or space separated string of keys
// 支持删除数组格式的key
if ( Array.isArray( key ) ) {
// If key is an array of keys...
// We always set camelCase keys, so remove that.
key = key.map( camelCase );
// 如果参数key不是数组,则将其封装或解析成为数组
} else {
// 为了保持一致,强行的构造了一个数组
key = camelCase( key );
// If a key with the spaces exists, use it.
// Otherwise, create an array by matching non-whitespace
//如果存在空格键,就使用它。否则,通过匹配非空格创建数组
key = key in cache ?
[ key ] :
( key.match( rnothtmlwhite ) || [] );
}
i = key.length;
// 遍历参数name中得数据名,用运算符delete逐个从数据缓存对象cache中移除。
while ( i-- ) {
delete cache[ key[ i ] ];
}
}
// Remove the expando if there's no more data
// cache为空的时候,删除整个缓存
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
// Support: Chrome <=35 - 45
// Webkit & Blink performance suffers when deleting properties
// from DOM nodes, so set to undefined instead
// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
// 删除扩展得jQuery.expando属性
// Webkit和Blink在删除DOM节点属性时会影响性能,因此将其设置为undefined
if ( owner.nodeType ) {
owner[ this.expando ] = undefined;
// 否则直接删除
} else {
delete owner[ this.expando ];
}
}
},
hasData: function( owner ) {
var cache = owner[ this.expando ];
return cache !== undefined && !jQuery.isEmptyObject( cache );
}
};
var dataPriv = new Data();
var dataUser = new Data();
jQuery.extend( {
// 代码行:4232——4234
// 方法jQuery.removeData()用于移除通过jquery.data()设置得数据,通过调用dataUser.remove(elem, name)实现。
removeData: function( elem, name ) {
// 参数elem:待移除数据的DOM元素或JavaScript对象。
// 参数name:待移除的数据名,可以时单个数据名、数据名数组、用空格分隔得多个数据名。
dataUser.remove( elem, name );
},
_removeData: function( elem, name ) {
dataPriv.remove( elem, name );
}
} );
// 代码行:4247——4328
jQuery.fn.extend( {
// 代码行:4323——4327
// 方法.removeData(key)用于移除匹配元素得自定义数据,通过在每个匹配元素上调用方法dataUser.remove()实现。
removeData: function( key ) {
return this.each( function() {
dataUser.remove( this, key );
} );
}
} );