jQuery源码分析之prop和removeProp方法

DOM对象实例方法prop源码:

	prop: function( name, value ) {
		return access( this, jQuery.prop, name, value, arguments.length > 1 );
	}
如果传入一个参数,那么这时候value是undefined,第五个参数是false,为了方便我们还是附上access源码:

如果是获取属性(value是false,chainable和bulk都是false):调用fn(elem[0],key)那么回调jQuery.prop方法,传入参数第一个DOM对象和key值,也就是只是获取第一个DOM对象的属性值!这和attr获取时候的结果是一样的!

如果是设置属性:传入access里面第三个和第四个参数都存在,同时第五个参数是true,这时候为每一个调用对象的DOM对象都调用jQuery.prop方法传入的参数是DOM元素,key和value。如prop("prop_a","codePlayer")

var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
	var i = 0,
		length = elems.length,
		bulk = key == null;
	// Sets many values
	if ( jQuery.type( key ) === "object" ) {
		chainable = true;
		for ( i in key ) {
			jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
		}
	// Sets one value
	} else if ( value !== undefined ) {
		chainable = true;
		if ( !jQuery.isFunction( value ) ) {
			raw = true;
		}
		if ( bulk ) {
			// Bulk operations run against the entire set
			if ( raw ) {
				fn.call( elems, value );
				fn = null;

			// ...except when executing function values
			} else {
				bulk = fn;
				fn = function( elem, key, value ) {
					return bulk.call( jQuery( elem ), value );
				};
			}
		}
		if ( fn ) {
			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;
};
jQuery.prop方法源码: 你要弄明白如果不通过下标形式对DOM赋值获得property属性,那么document.getElementById("n2").data_key就是false,但是这都

算是attribute!但是property和attribute也有交叉的地方,如id,calss和className等(可以通过firebug看出)。

jQuery.extend({
	propFix: {
		"for": "htmlFor",
		"class": "className"
	},
//prop里面调用prop(elem[0],"name")
	prop: function( elem, name, value ) {
		var ret, hooks, notxml,
			nType = elem.nodeType;
		// don't get/set properties on text, comment and attribute nodes
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}
       //不是XML元素
		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
		if ( notxml ) {
			// Fix name and attach hooks
			//获取hooks,如果这个hooks已经存在,也就是内置的几种如selected,href,src等那么调用内部的set方法或者get方法
                       //如jQuery.propHooks["select"]就是内置的对象
			name = jQuery.propFix[ name ] || name;
			hooks = jQuery.propHooks[ name ];
		}
      //如果value不为空表示设置
		if ( value !== undefined ) {
			//设置成功返回set方法的返回值,否则返回elem的相应属性.但是必须注意:这里的propHooks里面的属性是固定的
			return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
				ret :( elem[ name ] = value );
		} else {
			//获取相应属性
			return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
				ret :
				elem[ name ];
		}
	},

propFix:对tabindex等进行的处理

jQuery.each([
	"tabIndex",
	"readOnly",
	"maxLength",
	"cellSpacing",
	"cellPadding",
	"rowSpan",
	"colSpan",
	"useMap",
	"frameBorder",
	"contentEditable"
], function() {
	jQuery.propFix[ this.toLowerCase() ] = this;
});

IE6/7下面enctype是encoding

// IE6/7 call enctype encoding
if ( !support.enctype ) {
	jQuery.propFix.enctype = "encoding";
}
for修改为htmlFor,class是className,所以对于prop方法来说可以传入for也可以传入htmlFor等
	propFix: {
		"for": "htmlFor",
		"class": "className"
	}

tabIndex来说jQuery做了特殊的处理,也就是说我们获取tabIndex的时候是调用该hooks中的get!

      var rfocusable = /^(?:input|select|textarea|button|object)$/i,
	rclickable = /^(?:a|area)$/i;	
     propHooks: {
    		tabIndex: {
			get: function( elem ) {
				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				// Use proper attribute retrieval(#12072)
				var tabindex = jQuery.find.attr( elem, "tabindex" );//因为tabIndex如果没有设置可能会返回不正确的值!
                                     //这里还是调用jQueyr.find.attr方法,不过传入的不是驼峰写法!如果调用该方法没有获取到有效的tabIndex
                                     //那么要对标签进行判断,如果是input/select/textarea/button/object那么返回0;如果是a/area同时有href
                                    //也返回0,否则返回-1!
				return tabindex ?
					parseInt( tabindex, 10 ) :
					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
						0 :
						-1;
			}
		}//End of tabIndex
	}
});
对hrefNormalize进行分析:该方法判断是否能够获取到有效的href值!如果是返回true!

div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
	a = div.getElementsByTagName("a")[ 0 ];
     support.hrefNormalized = a.getAttribute("href") === "/a";

如果不能获取到有效的href属性值,那么我们用getAttribute("href")或者getAttribute("src")等,至于为什么加入第二个参数是为了在IE6/7下获取完整的src/href属性!

//如果获取hooks是undefined,那么直接返回elem[key]的值!
//我们看看jQuery中对propHooks进行设置的代码:
//代码一之href和src:
if ( !support.hrefNormalized ) {
	// href/src property should get the full normalized URL (#10299/#12915)
	jQuery.each([ "href", "src" ], function( i, name ) {
		jQuery.propHooks[ name ] = {
			get: function( elem ) {
				return elem.getAttribute( name, 4 );
			}
		};
	});

 

optSelected属性测试:

	// Make sure that a selected-by-default option has a working selected property.
	// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
	select = document.createElement("select");
	opt = select.appendChild( document.createElement("option") );
	support.optSelected = opt.selected;
检测当一个option添加到select上时候该option是否被选中,也就是他的selected是否是true,如果是true表示被选中,如果是false表示没有被选中!如果没有被选中的时候我们要做兼容!也就是默认第一项被选中!

// Support: Safari, IE9+
// mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
//IE9+和Safari会错误的得到option的默认的selected属性,通过获取他父元素的selectedIndex解决这个bug
if ( !support.optSelected ) {
	jQuery.propHooks.selected = {
		get: function( elem ) {
			var parent = elem.parentNode;
			if ( parent ) {
				parent.selectedIndex;
				// Make sure that it also works with optgroups, see #5701
				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
			return null;//返回null,所以在prop方法里最后返回的还是elem["selected"]
		}
	};
}

jQuery中暂时没有找到其它的地方对jQuery.propHooks进行赋值。设置值的时候这个hook不存在,那么就会 调用elem[key]=value进行赋值!但是在attr方法中调用的是setAttribute方法!
总结:

(1)如果使用prop()函数操作表单元素的checkedselecteddisabled等属性,如果该元素被选中(或禁用),则返回true,否则(意即HTML中没有该属性)返回false。之所以是这样还是因为底层用的是property访问的方法,不是用getAttribute方法!不选中的时候property返回false,attribute返回null!
(2)prop()函数还可以设置或返回DOM元素的Element对象上的某些属性,例如:tagName、selectedIndex、nodeName、nodeType、ownerDocument、defaultChecked和defaultSelected等属性。之所以能够获取是因为每一个元素在firebug下都能看到这个property!是property不是attributes,而且这些属性是不能被改变的,也就是说如果你把tagName设置为新的值,那么再次获取还是原来的值!

(3)在IE9及更早版本中,如果使用prop()函数设置的属性值不是一个简单的原始值(String、Number、Boolean),并且在对应的DOM元素被销毁之前,该属性没有被移除,则可能会导致内存泄漏问题。如果你只是为了存储数据,建议你使用data()函数,以避免内存泄漏问题。
(4)但是从1.6开始,使用attr()获取这些属性的返回值为String类型,如果被选中(或禁用)就返回checkedselecteddisabled,否则(即元素节点没有该属性)返回undefined。并且,在某些版本中,这些属性值表示文档加载时的初始状态值,即使之后更改了这些元素的选中(或禁用)状态,对应的属性值也不会发生改变。1.11.1就是这样

(5)因为tabIndex如果没有设置可能会返回不正确的值!这里还是调用jQueyr.find.attr方法,不过传入的不是驼峰写法!如果调用该方法没有获取到有效的tabIndex那么要对标签进行判断,如果是input/select/textarea/button/object那么返回0;如果是a/area同时有href也返回0,否则返回-1!

(6)如果用prop方法访问for属性,可以用htmlFor也可以用for,因为prop方法有专门针对他的propFix,如果用attr访问for属性那么就只能是attr("for"),对于class也是一样的!(记住:这时候prop方法要变成驼峰)

(7)针对IE6/7获取URL会被修改的情况下,IE调用getAttribute方法时候传入了第二个参数为4,那么就能和其它浏览器一样不会串改URL!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值