曾经发表过的关于data的博文:使用 data-* 属性来嵌入自定义数据,想对data定义数据有深入了解的小伙伴请转至那篇博文,今天将再次提及data-*属性,以及在使用Jquery时如果要再DOM上储存数据(jquery的data方法):
1 2 3 4 5 6
| var elem = $('#elem'); elem.data(key,value);
var elem = $('#elem'); $.data(elem[0],key,value);
|
解释原因为:后一种写法要比前一种写法,快了将近10倍。因为elem.data()方法是定义在jQuery函数的prototype对象上面的,而$.data()方法是定义jQuery函数上面的,调用的时候不从复杂的jQuery对象上调用,所以速度快得多。
乍一看可能有点懵逼,去W3School上找这两种方法,可以看到解释概念不太一样,点进去后却发现两个方法的内容几乎完全一样,顿时有种被骗的感觉:
没关系,今天我们就是要详细说说这两种形式的区别。
如果看过Jquery源码也许会发现对于jquery的extend有两种使用方式,
第一种:jQuery.extend();>
第二种:jQuery.fn.extend();
其实往简单的说,就是$.extend()和$.fn.extend()用法和区别。
我们自己写jquery插件时候应该常用到这两种函数,乍一看很像,其实两个函数差别还是很大,下面具体讲讲有什么区别
1、$.extend()
该方法用于扩展jQuery类,它的方法是全局的,直接用jquery类便可以引用:
1 2 3 4 5 6
| $.extend({ getName:function(name){ return name; } }); $.getName("侠名风");
|
通常我们把这类函数称作为工具函数,它们不直接操作DOM元素,而是操作Javascript的非元素对象,或者执行其他非对象的特定操作。
2、$.fn.extend()
该方法则是用来扩展jQuery的实例方法,也就是说jQuery类的实例对象可以调用此函数(你也可以理解为操作dom来实现),代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <html> <head> <script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ $.fn.extend({ sayHello:function(){ alert("你好,侠名风!"); } }) $("#btn").click(function(){ $(this).sayHello() }); }) </script> </head> <body> <div id="btn">点我</div> </body> </html>
|
该例子通过$.fn.extend()方法为jQuery扩展一个实例方法,那么就必须要用对象实例来调用此方法,$(“#btn”)就是一个对象实例,这样它就可以调用添加的方法。
有的人会问了,你不是在讲data吗?干嘛扯出来extend?别急,那么回到我们最初的问题,data这两种方式跟extend有何区别?
打开jquery源码,我这里以jquery最新的2.2.1版本作为例子讲解。
1、elem.data(key,value);
查看jQuery源码关于data此形式定义的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| jQuery.fn.extend( { data: function( key, value ) { var i, name, data, elem = this[ 0 ], attrs = elem && elem.attributes;
if ( key === undefined ) { if ( this.length ) { data = dataUser.get( elem ); if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { i = attrs.length; while ( i-- ) { if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } } dataPriv.set( elem, "hasDataAttrs", true ); } }
return data; } if ( typeof key === "object" ) { return this.each( function() { dataUser.set( this, key ); } ); } return access( this, function( value ) { var data, camelKey; if ( elem && value === undefined ) { data = dataUser.get( elem, key ) || dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() ); if ( data !== undefined ) { return data; } camelKey = jQuery.camelCase( key ); data = dataUser.get( elem, camelKey ); if ( data !== undefined ) { return data; } data = dataAttr( elem, camelKey, undefined ); if ( data !== undefined ) { return data; } return; } camelKey = jQuery.camelCase( key ); this.each( function() { var data = dataUser.get( this, camelKey ); dataUser.set( this, camelKey, value ); if ( key.indexOf( "-" ) > -1 && data !== undefined ) { dataUser.set( this, key, value ); } } ); }, null, value, arguments.length > 1, null, true ); }, } );
|
值得注意的是data会获取多个对象,但是返回的只有一个对象(值)。
由此可以看出,使用elem.data(key,value)会执行]jQuery.fn.extend()中的data方法,代码量真不少啊。
2、$.data(elem[0],key,value);
此种方式代码相简洁接很多了…
1 2 3 4 5 6 7
| jQuery.extend( { data: function( elem, name, data ) { return dataUser.access( elem, name, data ); }, } );
|
可能你会问,也许代码都封装在dataUser.access中了,我书读得少你别骗我。
那我们看看这个data.access里都有些什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Data.prototype = { access: function( owner, key, value ) { var stored; if ( key === undefined || ( ( key && typeof key === "string" ) && value === undefined ) ) { stored = this.get( owner, key ); return stored !== undefined ? stored : this.get( owner, jQuery.camelCase( key ) ); } this.set( owner, key, value ); return value !== undefined ? value : key; }, }
|
其实access方法在第一种方式中返回时也调用,而由于html5的data标签和很多判断绕了许多弯路,使用jquery函数上上的data方法更加直接效率更高。那么有人会问了,那我们以后都用第二种方式还需要第一种干嘛?这就要讲讲elem.data(key,value)和$.data(elem[0],key,value)的区别了。
先看下面的例子:
1 2 3 4 5 6 7 8 9
| var div1 = $("div"), div2 = $("div"); div1.data('key',"1"); div2.data('key',"2"); console.log(div1.data('key'),div2.data('key'));
$.data(div1,'key','1'); $.data(div2,'key','2'); console.log($.data(div1,'key'),$.data(div2,'key'));
|
你看出区别了吗$.data(div1, “key”, “1”)的方法会根据elem的不同创建不同的对象来进行存储数据, div1.data(“key”, “1”)的方法则替换掉了原来的数据。
讲了这么多总结一下:
1、如果在全局定义变量,而要在每次方法中替换data值用第一种方式(elem.data(key,value));
2、如果是为了获取并赋值dom的data并且记录每次改变的值,推荐使用第二种形式($.data(elem[0],key,value));
3、还有一点需要注意:jquery-data是单向绑定,不会因为你改变data而联动改变html5中data-属性值,切记;