两个方法很相似,但是有区别,简单说一下:

$.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的方法本质是一样的,实例方法是静态方法的扩展,底层存储读取还是掉用的静态方法

随机推荐

  1. 第一百零七节,JavaScript基本包装类型,数据类型的方法

    JavaScript基本包装类型,数据类型的方法 学习要点: 1.基本包装类型概述 2.Boolean类型 3.Number类型 4.String类型 为了便于操作基本类型值,ECMAScript提供 ...

  2. about hibernate lazy load and solution

    about hibernate lazy load is that used when loaded again.it can increase efficienty and sava memory. ...

  3. Spring Security(02)——关于登录

    目录 1.1     form-login元素介绍 1.1.1    使用自定义登录页面 1.1.2    指定登录后的页面 1.1.3    指定登录失败后的页面 1.2     http-basi ...

  4. Android启动另一个APP时,注意disable与enable的问题

    在写游戏sdk时候遇到了一个需要在sdk中通过scheme来启动支付宝的免密支付功能,所以需要在设备中通过包名检查一下支付宝是否存在. 此时遇到了一个问题,在三星设备中可以将app给处于disable ...

  5. 判断括号字符串是否为合法+求n对括号的所有组合

    n对括号的有效组合数 参考:https://zh.wikipedia.org/wiki/%E5%8D%A1%E5%A1%94%E5%85%B0%E6%95%B0 import java.util.Ar ...

  6. 如何在Excel中少犯二(I)

    作者:何明科链接:https://zhuanlan.zhihu.com/p/23472480来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 收到不少建议,要求开知乎Li ...

  7. Java 水仙花数

    小小练习大神掠过吧 题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个"水仙花数&quo ...

  8. NOIP2011-普及组复赛-第二题-统计单词数

    题目描述 Description 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数.  现在,请你编程实现这一功能,具体要求是:给 ...

  9. HTML转PDF

    1)使用工具转换.如:wkhtmltopdf 2)Chrome浏览器打印功能中,有另存为PDF格式文件.(推荐最便捷)

  10. 移动端touch触屏滑动事件、滑动触屏事件监听!

    一.触摸事件 ontouchstart.ontouchmove.ontouchend.ontouchcancel 目前移动端浏览器均支持这4个触摸事件,包括IE.由于触屏也支持MouseEvent,因 ...