$.data()、$().data
两个方法很相似,但是有区别,简单说一下:
$.data():jq的静态方法,也就是jQuery.data()直接调用
$().data():实例方法,先有实例,才能调用这个方法,例如:$("#id").data("name","zhangsan")
区别:
通过例子说下:
var div1 = $("#d1");
var div2 = $("#d1");
$.data(div1, "name", "zhangsan");
$.data(div2, "name", "lisi");
document.write($.data(div1).name);//zhangsan
document.write($.data(div2).name);//zhangsan
div1.data("name", "zhangsan");
div2.data("name", "lisi");
document.write(div1.data("name"));//lisi
document.write(div2.data("name"));//lisi
顺便说一下他们定义的来源,$.extend(),$.fn.extend();这篇文章讲的不错,大家可以看一下http://caibaojian.com/jquery-extend-and-jquery-fn-extend.html
$.extend():增加全局函数、对象,相当于给jQuery这个类增加了静态方法
$.fn.extend():这个是对jQuery.prototype进得扩展(原来 jQuery.fn = jQuery.prototype),就是为jQuery类添加“成员函数”
ok,进入正题,先来看静态方法:$.data();
举几个例子:
$.data($("#id"),"name","zhangsan");
$.data({},"name","zhangsan");
$.data({},{"name",function(){}});
等等jQuery.extend({
data: function( elem, name, data ) {
return internalData( elem, name, data );
}
...
}
//内部方法
function internalData( elem, name, data, pvt /* Internal Use Only */ ){
//检测这个elem是否可接受数据
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, ret,
//随机号,jquery加载的时候初始化它,expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" )
internalKey = jQuery.expando,
//name是string类型为true
getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
// 必须区分处理DOM元素和JS对象,因为IE6-7不能垃圾回收对象跨DOM对象和JS对象进行的引用属性(这个目前还不太懂)
isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
//如果是dom节点,则cache取jq全局的cache,否则取elem本身,这个有点意思
cache = isNode ? jQuery.cache : elem,
// 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
//如果已经存在cache,则直接取,如果不存在则undefined
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; // Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
//对象没有任何数据,直接返回
if ( (!id || !cache[id] || (!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
//如果是dom节点,则添加internalKey/guid这个键值对到elem上,方便以后调用
if ( isNode ) {
elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
} else {//非dom节点,比如自己创建的对象{}
id = internalKey;
}
}
//cache[id]不存在则添加一个空对象
if ( !cache[ id ] ) {
cache[ id ] = {}; // Avoids exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
//废掉cache[id]的toJSON方法,防止这个对象进行序列化通过toJSON方法,从而暴露jQuery的元数据(还不太理解)
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
//如果是对象或者函数,则浅克隆它到cache[id]的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 );
}
} 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.
//不是内部元素的话定义赋值cache相关属性
if ( !pvt ) {
//cache[id].data不存在则创建
if ( !thisCache.data ) {
thisCache.data = {};
}
//单独取出data对象
thisCache = thisCache.data;
}
//如果此处data有定义,则把name/data赋值到cache.data的上面,即cache.data={name:data}
if ( data !== undefined ) {
//camelCase这个函数是驼峰函数,进行一些大小写的,如a-and-b-》aAndB
thisCache[ jQuery.camelCase( name ) ] = data;
} // Check for both converted-to-camel and non-converted data property names
// If a data property was specified
如果name是String类型的,则取对应的data值(“zhangsan”),否则返回cache中的data对象({name:funciton(){}})
if ( getByName ) { // 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;
}
再来看看实例data方法的定义:
jQuery.fn.extend({
data: function( key, value ) {
var attrs, name,
elem = this[0],
i = 0,
data = null; // Gets all values
//当key不存在,data();
if ( key === undefined ) {
if ( this.length ) {
//取elem的缓存
data = jQuery.data( elem );
//如果是element对象并且没有被解析过,如果被解析过,cache中存在{parseAttrs:true}
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
attrs = elem.attributes;
//取所有属性,然后进行遍历
for ( ; i < attrs.length; i++ ) {
name = attrs[i].name;
//查找html5的属性例如data-option
if ( !name.indexOf( "data-" ) ) {
name = jQuery.camelCase( name.slice(5) );
//以驼峰命名的方式,取出那么,并且存到缓存中,data[name]先取缓存,如果存在则不缓存,不存在的话进行缓存
dataAttr( elem, name, data[ name ] );
}
}
//比较已经解析过此elem,设置此元素对应的cache的parseAttrs字段为true
jQuery._data( elem, "parsedAttrs", true );
}
} return data;
} // Sets multiple values
//当key是object类型的时候,例如:{"name":"john"}
if ( typeof key === "object" ) {
//遍历this,用key赋值,通常这里的this都是实例的数组形式
return this.each(function() {
//通过静态方法存储key,这时候这里的this就是dom元素了,有上面的data源码分析可以知道,他是存储在jQuery.cache
//意味着,如果一个再存储一个值,比如{"name":"zhangsan"},则会替换原先的cache的值
jQuery.data( this, key );
});
}
//当key存在且不是object的时候,返回一个函数,这个access中就是参数中function的调用(value值存在的时候调用一次,value值不存在的时候还调用),简单数一下这个参数中的function
return jQuery.access( this, function( value ) {
//value不存在的时候说明是get方法,从缓存中取值
if ( value === undefined ) {
// Try to fetch any internally stored data first
//先用jQuery.data(elem,key)取出值ret,dataAttr判断ret的值,存在则返回,不存在则进一步判断这个key是否是html5元素,是的话取值,并存储
return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
} this.each(function() {
//存储key-value
jQuery.data( this, key, value );
});
}, null, value, arguments.length > 1, null, true );
}, removeData: function( key ) {
return this.each(function() {
jQuery.removeData( this, key );
});
}
});
/*
* @param elems jQuery的this
* @param fn 函数
* @param key 属性
* @param value 值
* @param chainable 是否可以链式调用,如果是get动作,为false,如果是set动作,为true
* @param emptyGet 如果jQuery没有选中到元素的返回值
* @param raw value是否为原始数据,如果raw是true,说明value是原始数据,如果是false,说明raw是个函数
* @returns {*}
*/
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
length = elems.length,
bulk = key == null; // Sets many values
//这个access方法是复用的,虽然data的方法没传值,其它方法调用如: attr: function (name, value) {return jQuery.access(this, jQuery.attr, name, value, arguments.length > 1);}
if ( jQuery.type( key ) === "object" ) {
chainable = true;
//当key是{"name":"value"}的时候,把链式操作设置为true,然后递归调用access方法
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
} // Sets one value
//key!=object并且value存在(这里包括了key==null)
} else if ( value !== undefined ) {
chainable = true;
//value不是function
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
//key==null
if ( bulk ) {
// Bulk operations run against the entire set
// key==null并且value存在还不是function,调用fn函数,之后设置为null
if ( raw ) {
fn.call( elems, value );
fn = null; // ...except when executing function values
} else {// key==null并且value===function,bulk存储原来的fn函数,fn指向一个新函数(返回bulk函数的调用,即原来fn的调用)
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
//如果fn存在,无论是否被修改过,即fn的指向是否有变
if ( fn ) {
for ( ; i < length; i++ ) {//循环elems调用fn
fn( elems[i], key,
raw ? value :
//value不是function的话直接取value,是function则直接调用,下面摘录一下网上的解释,引用的attr的方法,如下:
/**
attr: function (name, value) {
return jQuery.access(this, jQuery.attr, name, value, arguments.length > 1);
},
* 如果value是原始数据,就取value,如果是个函数,就调用这个函数取值
* $('#box').attr('abc',function (index,value) { index指向当前元素的索引,value指向oldValue
*
* 先调用jQuery.attr(elements[i],key) 取到当前的值,然后调用传入的fn值
* });
*/
value.call( elems[i], i, fn( elems[i], key ) ) );
}
}
}
/**引用一下网上的解释
* 如果chainable为true,说明是个set方法,就返回elems
* 否则说明是get方法
* 1.如果bulk是个true,说明没有key值,调用fn,将elems传进去
* 2.如果bulk为false,说明key有值哦,然后判断元素的长度是否大于0
* 2.1 如果大于0,调用fn,传入elems[0]和key,完成get
* 2.2 如果为0,说明传参有问题,返回指定的空值emptyGet
*/
return chainable ?
elems : // Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
}
看完源码之后,你会发现,两个data的方法本质是一样的,实例方法是静态方法的扩展,底层存储读取还是掉用的静态方法
随机推荐
- ImageView.ScaleType设置图解
图文相配很清晰的看出每个属性的效果, 感觉 CENTER_CROP 比较有用,长宽自动适应 ImageView ,整个图片自动缩略填充整个区域且居中显示(高宽不一定是view的尺寸),以前用JS在网页 ...
- PHP学习过程_Symfony_(1)
从今天开始学习php,感兴趣的同学欢迎一块讨论学习,QQ群新群182983780; 1:配置环境变量 把这php和php5http://pan.baidu.com/s/1pKDq9tT两个文件同时c盘 ...
- iOS开发下架在AppStore中销售的app
1.登陆开发者账号 2.选择itunes connect 选择我的app 3.选择要下架的app 4.价格与销售范围 5.销售范围 6.点击存储 //如果想要重新在AppStore中进行销售只需要选择 ...
- button,input type=button按钮在IE和w3c,firefox浏览器区别
在项目中遇到一个问题,是关于点击button按钮会自动刷新的问题.查阅了资料,做以下的整理: button,input type=button按钮在IE和w3c,firefox浏览器区别如下:当在IE ...
- 高效PHP程序必知的53个技巧
用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说 ...
- B树(B-树)
1.什么是B树(B-树)? B树是一种m阶树,m>=2 性质: 1)树中每个结点至多m个孩子: 2)对于根结点,子树个树取值范围为[2,m],关键字个数范围[1,m-1]: 3)对于非根非叶结点 ...
- ARC 下面可能导致的内存问题
一.ARC相对MRC来说,减轻了程序员的大部分内存管理工作,使用ARC的时候也需要十分清除内存管理的原理,不然可能带来一些很难调试的问题.下面是ARC下面需要注意的一些问题 1)对象互相引用,形成引用 ...
- 对一个表中所有列数据模糊查询adoquery
如何用adoquery对一个表中所有列进行模糊查询: procedure TForm3.Button4Click(Sender: TObject); var ASql,AKey: string; I: ...
- 使用Apache + mod_jk + tomcat来实现tomcat集群的负载均衡出现的无法加载mod_jk.conf文件的问题
用Apache + mod_jk + tomcat来实现tomcat集群的负载均衡的 如果出现了问题,可以用cmd cd到Apache安装文件的bin下,运行httpd文件,错误信息就会打印出来. ...
- NTFS 读写高手进阶 - Windows 格式硬盘 Mac存文件 开启 ...(转载)
常识: 硬盘格式: FAT32 - WIndows 硬盘分区格式, 有点通用性高, 缺点不支持单个大于 4G 的文件. exFAT - Windows 硬盘分区格式, 兼容性低. 稳定性不如 FAT3 ...