目录node
转载请注明出处数组
@浏览器
1..attr()的四种用法
大体用法:函数
用法详解:
(1)..attr()源代码定义:this
jQuery.fn.extend( { attr: function( name, value ) { return access( this, jQuery.attr, name, value, arguments.length > 1 ); } }
可见,.attr的核心是函数access(),而该函数不须要实例便可调用,属于直接定义在jQuery上的'静态函数'.code
jQuery.access()源代码定义:对象
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, length = elems.length, bulk = key == null; //bulk用于判断key值是否为null(注:null==undefined的结果为true) // 设置多个值(当key参数为对象时,注:jQuery.type实现原理是[[class]]) if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); } // 设置一个值(当key为非对象类型时) } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; //判断value值是否为函数类型.若是不是函数,设置raw值,为if(fn)以及if(bulk)埋下伏笔 } if ( bulk ) { //批处理 // 批处理是执行在整个属性集上的 if ( raw ) { fn.call( elems, value ); fn = null; // 当value为函数时又有点不一样 } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { //对elems中的每个元素应用fn方法,第三个参数由raw决定 for ( ; i < length; i++ ) { fn( elems[ i ], key, raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } } return chainable ? //返回值设定 elems : // Gets bulk ? fn.call( elems ) : length ? fn( elems[ 0 ], key ) : emptyGet; }
如上图,因为access函数用途并不局限于咱们的.attr(),做为像笔者同样的jQuery初学者,源代码中有许多代码语句咱们不能很好的理解(好比:if(bulk)部分).因为暂时接触到的jQuery内容较少较浅,咱们若是一味深究,可能既搞不清楚原理,还浪费时间.因此,咱们能够用一种简化的思想来分析问题: 只关注代码中跟咱们当前问题有关的部分,忽略无关的,用不到的部分.递归
具体作法:咱们将.attr()的四种用法的实际传参状况带入jQuery.access函数的定义中,删除咱们进不去的if语句代码块,只保留会用到的代码语句.索引
attr定义:接口
attr: function( name, value=undefined ) { return jQuery.access( this, jQuery.attr, name, value=undefined, arguments.length > 1 ); }
access调用简化:
var access = function( this, jQuery.attr, name, value=undefined, chainable=false, emptyGet=undefined, raw=undefined ) { var i = 0, length = this.length, //jQuery对象的length属性(jQuery对象老是有length属性,它是类数组对象) bulk = false; return jQuery.attr( this[0], name ); };
一样,咱们找到jQuery.attr()静态方法的源代码定义,用一样的简化方法分析,获得:
jQuery.attr()完整源码:
attr: function( elem, name, value ) { // elem:DOM对象 name:属性名/键名 value:属性值 var ret, hooks, nType = elem.nodeType; // 节点类型 // 屏蔽属性节点,文本节点与注释节点 if ( nType === 3 || nType === 8 || nType === 2 ) { return; } // 当属性不支持getAttribute方法时,回调jQuery.prop()方法--从操做attribute变成了操做property if ( typeof elem.getAttribute === "undefined" ) { return jQuery.prop( elem, name, value ); } //下面的都是DOM元素elem支持getAttribute的状况 // 全部标签特性(attributes)都是小写(处理兼容:有的浏览器对同一属性的名称可能大小写不停) // 若是某一个是已定义的,抓取必要的钩子 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { // 非元素节点或者是XML文本中的元素 name = name.toLowerCase(); hooks = jQuery.attrHooks[ name ] || ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); } if ( value !== undefined ) {//若是value在传参时未被忽略 if ( value === null ) { jQuery.removeAttr( elem, name );//传入第三个参数为null时,调用jQuery.removeAttr移除对应属性 return; } if ( hooks && "set" in hooks && ( ret = hooks.set( elem, value, name ) ) !== undefined ) { return ret; } elem.setAttribute( name, value + "" ); return value; } if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { return ret; } ret = jQuery.find.attr( elem, name ); // 不存在的属性会返回null,咱们将之统一为undefined return ret == null ? undefined : ret; }
jQuery.attr()简化:
attr: function( elem, name, value=undefined ) { // elem:DOM对象 name:属性名/键名 value:属性值 var ret, hooks, nType = 1; ret = jQuery.find.attr( elem, name ); return ret; }
其中,惟一不肯定的是jQuery.find.attr,然而咱们继续找下去则是有关Sizzle选择器引擎的问题,这对于咱们初学者来讲过于复杂.所以,咱们再简化一下,带入实际情景,检测这一函数的输出:
var $p = $('#jQueryTest')[0]; console.log(jQuery.find.attr($p,'id')); //jQueryTest
所以,大概知道该函数该种传参状况下的做用是返回指定DOM元素的指定属性的值.
1.由jQuery.access简化代码中的return jQuery.attr( this[0], name );
可知,只传入一个name参数的状况下,确实只会返回jQuery对象中的索引为'0'的DOM对象的指定属性的属性值.
2.由jQuery.att()完整代码中
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
可知:若是不支持get/setAttibute,那么原来的针对特性(attibute)的操做就会变成DOM元素属性(property)的操做.
attr定义:
attr: function( name, value) { //此时的this是一个类数组 return jQuery.access( this, fn=jQuery.attr, name, value, chainable=true); }
access调用简化:
var access = function( this, jQuery.attr, name, value, chainable=true, emptyGet=undefined, raw=undefined ) { var i = 0, length = this.length, //jQuery对象的length属性,表示找到的匹配的DOM元素的个数 bulk = false; chainable = true; if ( !jQuery.isFunction( value ) ) { //当value值不为函数时,设置raw为true,这是为了下一步if(jQuery.attr)中的raw判断作铺垫 raw = true; } if ( jQuery.attr ) { //jQuery.attr,为true for ( ; i < length; i++ ) { //用for循环是由于此时的this是一个包含多个DOM元素的jQuery对象 jQuery.attr( this[ i ], name, raw ? value : value.call( elems[ i ], i, jQuery.attr( this[ i ], name ) ) );//raw为true,也就是value不为函数时,用value做第三参数 } } } return this; //返回jQuery对象自己 };
而,咱们用简化的方法分析此种状况下的jQuery.attr(this,name,value):
attr: function( this[i], name, value ) { var ret, hooks, nType = this[i].nodeType; if ( value !== undefined ) { //判断为true,进入if语句 if ( value === null ) { jQuery.removeAttr( this[i], name );//若是value为null,删除该jQuery对象的全部匹配元素的指定属性 return; } this[i].setAttribute( name, value + "" );//设置当前DOM元素的指定属性的属性值 return value; } ret = jQuery.find.attr( this[i], name ); //删除了属性,返回null;不然,返回指定属性的属性值 return ret == null ? undefined : ret; //若是删除了指定属性,返回undefined;若是修改了属性,返回指定属性值 }
attr定义:
attr: function( name=attrObject ) { return jQuery.access( this, jQuery.attr, name=attrObject, value=undefined, false); }
access调用简化:
var access = function( this, fn, name, value=undefined, chainable=false, emptyGet=undefined, raw=undefined ) { var i = 0, length = this.length, //元素的length属性 bulk = false; // 设置多个value值 if ( jQuery.type( name ) === "object" ) { //若是传入的name形参为对象类型 chainable = true; for ( i in name ) { //对每个对象中的属性名及属性值再次调用自己(递归) access( this, fn, i, name[ i ], true, emptyGet, raw ); } } return elems; //返回jQuery对象自己 };
可见,对于一个由"属性-属性值"键值对构成的对象,会对其中的每个属性都调用access设置一次.因为代码中使用的for-in循环,因此enumerable为false的键值对是无效的.
attr定义:
attr: function( name, value=attrFn ) { return jQuery.access( this, jQuery.attr, name, value=attrFn, chainable=true ); }
access调用简化:
var access = function( this, jQuery.attr, name, value=attrFn, chainable=true, emptyGet=undefined, raw=undefined ) { var i = 0, length = this.length, //jQuery对象的length属性 bulk = false; chainable = true; if ( jQuery.attr ) { //true,进入if语句 for ( ; i < length; i++ ) { jQuery.attr( this[ i ], name, attrFn.call( this[ i ], i, jQuery.attr( this[ i ], name ) ) // 调用attrFn,其返回值做为第三个参数 ); } } return elems; // 返回jQuery对象自己 };
由attrFn.call( this[ i ], i, jQuery.attr( this[ i ], name ) )
可知,attrFn的参数限制就是源自这一行代码:(this[i]是调用attrFn的元素,后面两个是参数,一个是jQuery对象中的索引值,一个是当前元素的指定属性name的值的查询返回)
[特别注意:attrFn的两个参数虽然有规定,可是不须要咱们真的传参,而是函数体内部使用索引值或者当前属性值的一个接口]