data和attr、prop的作用类似 都是给元素添加属性,但是data可以防止DOM元素与对象之间的互相引用,从而防止出现内存泄漏的现象。
data的使用方法
data可以作为工具方法和实例方法使用
var obj = {};
$.data(obj,'name','hello');
$.removeData(obj,'name');
console.log($.data(obj))
$('#div1').data('name','hello');//设置
console.log($('#div1').data('name'));//获取
$('#div1').removeData('name')
data的原理
为了避免内存泄漏 data采用间接为元素添加属性的方法实现 data添加元素属性并不是添加到元素上,而是添加到了一个json数据中,通过在元素上添加一个唯一属性,让该属性与json数组建立联系。
jquery的最新版本(3.0.0)与以往的思想不同。 在该版本中,data添加属性时 将json直接赋值给了唯一属性名。这种方式如何避免内存泄漏,还未想明白
data源码分析
源码中有一个Data类(3.0.0),工具方法和实例方法都是基于这个Data类实现的,我们先看一下该类的实现
var acceptData = function( owner ) {
// Accepts only:
// - Node
// - Node.ELEMENT_NODE
// - Node.DOCUMENT_NODE
// - Object
// - Any
/* jshint -W018 */
//-----------------当owner为字符串 也返回true????????????
return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
};
function Data() {
// jQuery.expando jquery的版本加随机数
this.expando = jQuery.expando + Data.uid++; //唯一标示,表示data添加到元素中的属性名
}
Data.uid = 1;
Data.prototype = {
//给owner添加属性 owner可以为元素 对象
cache: function( owner ) {
// Check if the owner object already has a cache
// 检查元素中是否有该属性 如果没有就创建
var value = owner[ this.expando ];
// If not, create one
if ( !value ) {
value = {};
// We can accept data for non-element nodes in modern browsers,
// 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为文档节点 给owner赋值
if ( owner.nodeType ) {
//将owner[ this.expando ]赋值
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
} else {
//如果不存在就创建 这种方法创建的属性是不能被修改的
//object.defineProperty()方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象
Object.defineProperty( owner, this.expando, {
value: value,
configurable: true//表示能否把属性修改为访问器属性 能否通过delete删除属性
} );
}
}
}
return value;
},
//设置cache的值
set: function( owner, data, value ) {
var prop,
cache = this.cache( owner );
console.log(cache);
// Handle: [ owner, key, value ] args
// Always use camelCase key (gh-2257)
if ( typeof data === "string" ) {
//给cache添加属性和属性值
cache[ jQuery.camelCase( data ) ] = value;
// Handle: [ owner, { properties } ] args
} else {
// Copy the properties one-by-one to the cache object
// 若data为json 将json中的数据拷贝到cache中
for ( prop in data ) {
cache[ jQuery.camelCase( prop ) ] = data[ prop ];
}
}
return cache;
},
//获得cache中的属性值 若key为undefined 返回所有属性
get: function( owner, key ) {
return key === undefined ?
this.cache( owner ) :
// Always use camelCase key (gh-2257)
owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
},
//合并get方法和set方法
access: function( owner, key, value ) {
//若key未定义或key为字符串 value未定义 调用get方法 获取属性值
if ( key === undefined ||
( ( key && typeof key === "string" ) && value === undefined ) ) {
return this.get( owner, key );
}
this.set( owner, key, value );
return value !== undefined ? value : key;
},
remove: function( owner, key ) {
var i,
cache = owner[ this.expando ];
if ( cache === undefined ) {
return;
}
if ( key !== undefined ) {
// Support array or space separated string of keys
// 判断删除的可以是不是数组 若为数字 则同时删除数组中的所有项
if ( jQuery.isArray( key ) ) {
// 返回驼峰写法
key = key.map( jQuery.camelCase );
} else {
key = jQuery.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( rnotwhite ) || [] );
}
i = key.length;
while ( i-- ) {
delete cache[ key[ i ] ];
}
}
// Remove the expando if there's no more data
// 当key不存在时 清空cache
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
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 rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,//匹配json和数组
rmultiDash = /[A-Z]/g;
//该函数完成h5中的"data—"格式的属性值
function dataAttr( elem, key, data ) {
var name;
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
// 当data属性名不存在时 将寻找h5中的data-属性
if ( data === undefined && elem.nodeType === 1 ) {
name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
data = elem.getAttribute( name );
if ( typeof data === "string" ) {
try {
//将字符串类型的值转换为特定类型的值
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
// Only convert to a number if it doesn't change the string
//判断是否为数值字符串 如果是数值字符串 将该字符串转换为数值类型
+data + "" === data ? +data :
//判断字符串中的值是否为json或数组 如果是 将其转换为json或数组
rbrace.test( data ) ? JSON.parse( data ) :
data;
} catch ( e ) {}
// Make sure we set the data so it isn't changed later
dataUser.set( elem, key, data );
} else {
data = undefined;
}
}
return data;
}
data的工具方法和实例方法基本上都是对该类的调用 很容易理解 这里不再详解