jQuery的access方法测试笔记

测试代码1值access与普通对象的关系:

<div id="test">111</div>
<div id="child">1111111</div>
var access1 = jQuery.access1 = function( elems, fn, key, value, chainable, emptyGet, raw ) {
>ar i = 0,
length = elems.length,
 //第三个参数是可选的,通过它走不同的逻辑
ulk = key == null;
// alert(value) 
// Sets many values
 //如果第三个是[object Object]对象
if ( jQuery.type( key ) === "object" ) {
//表示链式调用,也就是回归调用access
chainable = true;
for ( i in key ) {
//对第三个参数迭代出键名
Query.access1( elems, fn, i, key[i], true, emptyGet, raw );
}
// Sets one value
//第二次迭代出object的"xxx","female"
//第一次回归调用的时候value是"xxx"
} else if ( value !== undefined ) {
chainable = true;
         //这一次不是value不是函数,是"xxx"
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
        //key是name,所以bulk是false,这里的if不会执行!bulk用于判断是否有键名!
if ( bulk ) {
// Bulk operations run against the entire set
//最后一个参数raw
if ( raw ) {
fn.call( elems, value );
n = null;


// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
 }
}
      //第二个参数是fn,就是回调函数
if ( fn ) {
//length就是选择器的DOM的个数,这里就是$("div").length,逐个调用fn函数,传入的参数是$("div")[i]
//第二个参数就是迭代出来的key这里"name","sex",如果raw是true那么就是第三个参数是"xxx","female"
//否则就是把这个value作为函数调用!
for ( ; i < length; i++ ) {
//第一次因为传入的是object对象,第一次递归调用时候key是"name",value是"xxx",来到这里length是2,所以调用两次
//第二次递归调用时候key是sex,value是female,同时length是2,所以在这里又调用两次,打印结果如下:
//[testnamexxx,object childnamexxx,object testsexfemale,childsexfemale]
//也就是说$("div")[0]会拿着传入的{name:"xxx",sex:"female"}对象调用两次,第一次传入的参数是name,xxx,第二次传入的参数是sex,female
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
  }
    }
        }
     //打印[true,true,true]表示第一次递归调用过后是true,第二次递归调用也是true,一开始的那一次也是true
   // alert(chainable);
  return chainable ?
    //因为三次的chainable都是true,所以三次返回的都是elems,因为递归过程中第一个参数一直是没有变化的,所以是$("div")
  elems :
 // Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
};
var elements=$("div");
var key={name:"xxx",sex:"female"}
//回调函数
var f=function(){alert(arguments[0].id+arguments[1]+arguments[2]);}
//打印"test",也就是返回值是$("div")对象!
alert(access1(elements,f,key)[0].id);
测试代码2之text方法与access关系:(html调用方式一样只是回调函数不一样)

var access1 = jQuery.access1 = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
length = elems.length,
 //第三个参数是可选的,通过它走不同的逻辑
bulk = key == null;
       // alert(value) 
// Sets many values
//如果第三个是[object Object]对象
if ( jQuery.type( key ) === "object" ) {
//表示链式调用,也就是回归调用access
chainable = true;
or ( i in key ) {
//对第三个参数迭代出键名
jQuery.access1( elems, fn, i, key[i], true, emptyGet, raw );
}
// Sets one value
//第二次迭代出object的"xxx","female"
//第一次回归调用的时候value是"xxx"
} else if ( value !== undefined ) {
chainable = true;
         //这一次不是value不是函数,是"xxx"
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
    //key是name,所以bulk是false,这里的if不会执行!bulk用于判断是否有键名!
if ( bulk ) {
// Bulk operations run against the entire set
//最后一个参数raw
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
} else {
//text方法走了这里的逻辑:bulk赋值为函数fn,同时fn设置为一个新的函数,形成闭包,在该fn里面调用bulk函数的,第一个是上下文this
//绑定到jQuery(elem)上面
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
 };
}
}
      //第二个参数是fn,就是回调函数
if ( fn ) {
for ( ; i < length; i++ ) {
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
//text方法走到这里的时候,给fn传入了三个参数,分别是this[i],key=null,raw为false,第三个参数无法调用因为null无法调用
//底层调用bulk方法,给bulk方法传入参数,分别为jQuery(this[i]),也就是外层的调用对象的第i个DOM对象,value是null
}
}
}
  //打印[true,true,true]表示第一次递归调用过后是true,第二次递归调用也是true,一开始的那一次也是true
 // alert(chainable);
return chainable ?
     //因为三次的chainable都是true,所以三次返回的都是elems,因为递归过程中第一个参数一直是没有变化的,所以是$("div")
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
};
jQuery.fn.extend({
text1:function( value ) {
//是否是根据是否传入参数判断是读取函数设置参数!
return jQuery.access1( this, function( value ) {
//在access里面调用了该函数,其中this是jQuery(elem[i])表示上下文,第二个参数value传入到这里,是"先谢谢"
//这里是打印n1,因为上面已经封装为jQuery对象了,所以用attr方法调用!
//alert(this.attr("id"));
//alert(value===undefined);这个条件只有在调用方式为:$("div").text1()时候满足!
return value === undefined ?
jQuery.text( this ) ://jQuery.text = Sizzle.getText;调用Sizzle的getText方法
//将这个id是n1的对象清空,添加"先谢谢"
this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
//传入的参数为"先谢谢","1"。在access1中key是null导致access里面bulk是true,value是"先谢谢",raw是undefined
}, null, value, arguments.length );
}
})
alert($("div").text1());//从返回值可以知道这是由用的是jQuery.text(this)的逻辑,打印出[1111,111]
$("div").text1("先谢谢");//这是设置值
测试代码3之access与attr("name","xx")的关系:(prop方法是一样的)
var access1 = jQuery.access1 = function( elems, fn, key, value, chainable, emptyGet, raw ) {
	var i = 0,
		//length为2
		length = elems.length,
		//bulk为false
		bulk = key == null;
   
	if ( jQuery.type( key ) === "object" ) {	
		chainable = true;
		for ( i in key ) {
			jQuery.access1( elems, fn, i, key[i], true, emptyGet, raw );
		}

	} else if ( value !== undefined ) {
		//chainable是true
		chainable = true;
		if ( !jQuery.isFunction( value ) ) {
			raw = true;
		}
		if ( bulk ) {
			// Bulk operations run against the entire set
			//最后一个参数raw
			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 );
				};
			}
		}
//给所有的elems逐个调用fn函数,也就是jQuery.attr函数,传入两个参数,第一个是$("div")[i],第二个是"name",第三个是"Hello",因为raw是true
		if ( fn ) {
			for ( ; i < length; i++ ) {
				fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );		
			}
		}
	}	
	return chainable ?
//返回$("div")
		elems :

		// Gets
		bulk ?
			fn.call( elems ) :
			length ? fn( elems[0], key ) : emptyGet;
};
jQuery.fn.extend({
	
	attr1: function( name, value ) {
		//调用access1方法时候前5个参数都有值,第五个是true
		return access1( this, jQuery.attr, name, value, arguments.length > 1 );
	}
})
//打印2,返回$("div")这是jQuery支持链式调用的关键!
alert($("div").attr1("name","Hello").length);
下面是jQuery.attr函数源码:

	// Hook for boolean attributes
			boolHook = {
		        set: function( elem, value, name ) {
					if ( value === false ) {
						// Remove boolean attributes when set to false
						jQuery.removeAttr( elem, name );
					} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
						// IE<8 needs the *property* name
						elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );

					// Use defaultChecked and defaultSelected for oldIE
					} else {
						elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
					}

					return name;
				}
			};

// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = {
set: function( elem, value, name ) {
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
if ( !ret ) {
elem.setAttributeNode(
(ret = elem.ownerDocument.createAttribute( name ))
);
}
ret.value = value += "";
// Break association with cloned elements by also using setAttribute (#9646)
if ( name === "value" || value === elem.getAttribute( name ) ) {
return value;
}
}
};
这里是jQuery.attr源码:

attr: function( elem, name, value ) {
		var hooks, ret,
		nType = elem.nodeType;
		// don't get/set attributes on text, comment and attribute nodes
		//不再text,注释,属性节点上添加属性
		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}
		// Fallback to prop when attributes are not supported
		//如果不支持getAttribute那么用jQuery.prop函数
		if ( typeof elem.getAttribute === strundefined ) {
			return jQuery.prop( elem, name, value );
		}
		// All attributes are lowercase
		// Grab necessary hook if one is defined
		//如果不是Element或者也不是XMLDoc文档
		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
			//属性名变成小写
			name = name.toLowerCase();
			//hooks
			//如果存在jQuery.attrHooks["name"]或者name满足下面的正则表达式设置为boolHook,否则为nodeHook
///^(?:checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$/i
			hooks = jQuery.attrHooks[ name ] ||
				( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
		}
            //存在value值,attr("name","xxxx")
		if ( value !== undefined ) {
            //如果value是null,注意这里是===不是==所以必须手动传递null
	   //这时候就会把elem上面的相应属性移除
			if ( value === null ) {
				jQuery.removeAttr( elem, name );
			} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
				return ret;

			} else {
				//存在属性值最终调用setAttribute方法
				elem.setAttribute( name, value + "" );
				return value;
			}
          //如果不存在属性值
		} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
			return ret;

		} else {
			//调用jQuery.find.attr方法
			//jQuery.find = Sizzle;调用Sizzle的attr方法,传入参数为元素和属性名
			ret = jQuery.find.attr( elem, name );
			// Non-existent attributes return null, we normalize to undefined
			//如果没有找到这个属性值,那么返回undefined,否则返回属性值
			return ret == null ?
				undefined :
				ret;
		}
	}
下面是access函数与html()源码,access运行逻辑和text一样只是回调函数不一样:

<pre name="code" class="html">html: function( value ) {
		return access( this, function( value ) {
			//获取this[0]对象
			var elem = this[ 0 ] || {},
				i = 0,
				l = this.length;
 //如果不传value值,那么就是获取值
			if ( value === undefined ) {
				return elem.nodeType === 1 ?
//rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g
					elem.innerHTML.replace( rinlinejQuery, "" ) :
					undefined;
			}

			// See if we can take a shortcut and just use innerHTML
			//如果value是string,不是script,style,link,如果支持
			//rnoInnerhtml = /<(?:script|style|link)/i,
			//rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i")
			//rleadingWhitespace = /^\s+/,
			//rtagName = /<([\w:]+)/,
			//rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
				( support.htmlSerialize || !rnoshimcache.test( value )  ) &&
				( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
				!wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
               //对符合条件的进行替换
				value = value.replace( rxhtmlTag, "<$1></$2>" );
				try {
					for (; i < l; i++ ) {
						// Remove element nodes and prevent memory leaks
						elem = this[i] || {};
		//如果是{}那么没有nodeType是undefined,之所以用这种方式是为了防止直接用undefined调用nodeType抛出异常
						if ( elem.nodeType === 1 ) {
							//清除数据防止内存泄漏,也就是用$.data保存的数据
							jQuery.cleanData( getAll( elem, false ) );
							//设置为value值
							elem.innerHTML = value;
						}
					}

					elem = 0;

		// If using innerHTML throws an exception, use the fallback method
				} catch(e) {}
			}
 //如果添加的是比如script或者link,style那么直接清空,然后把标签添加进去,但是必须调用转义!<script><\/script>
//结束标签如果没有转义,那么抛出uncaught SyntaxError.如果不是这些特殊的标签,我们也清空,然后把数据添加进去!
			if ( elem ) {
				this.empty().append( value );
			}
		}, null, value, arguments.length );
	}


 正则表达式测试1: 

<pre name="code" class="html"><pre name="code" class="html">var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g
/*该正则表达式前面有一个空格!*/
alert(rinlinejQuery.test(' jQuery112="123"'));
//这个正则表达式后面有一个g,所以第二个是false
alert(rinlinejQuery.test(' jQuery112="null"'));
var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/
/*该正则表达式前面有一个空格!*/
alert(rinlinejQuery.test(' jQuery112="123"'));
//这里没有g,所以第二个也输出true,你你弄懂原因了吗微笑
alert(rinlinejQuery.test(' jQuery112="null"'));
<div id="n1">我是 jQuery12="null"  xxx</div>
var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g;
alert($("#n1")[0].innerHTML.replace(rinlinejQuery,""));//打印"我是 xxx",也就是中间满足正则表达式部分被忽略了!,同时jQuery前面要空格。用innerHTML会产生一个负作用,就是如果在id是n1的元素内如果有空格,那么IE7/8会忽略空格,但是其它浏览器不会,于是当html方法的结果用于if判断时候要手动清除空格!参见博客

 
 
</pre>正则表达式测试2:</p><p><pre name="code" class="html"><pre name="code" class="html">var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video";
//RegExp需要双重转义!
var rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i");
//都是打印true
alert(rnoshimcache.test("<video />"));
alert(rnoshimcache.test("<video/>"));
$.support.leadingWhitespace//表示使用innerHTML赋值时候时报保留前面的空白符!
var rleadingWhitespace = /^\s+/;//恰面有空格
 正则表达式测试3: 

//这是匹配所有的HTML标签前面的部分,如<html,<body
var rtagName = /<([\w:]+)/;
wrapMap = {
		option: [ 1, "<select multiple='multiple'>", "</select>" ],
		legend: [ 1, "<fieldset>", "</fieldset>" ],
		area: [ 1, "<map>", "</map>" ],
		param: [ 1, "<object>", "</object>" ],
		thead: [ 1, "<table>", "</table>" ],
		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
		_default: $.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
	}
//rtagName表示只能是\w或者:
//匹配所有的标签
alert(rtagName.test("<table>"));
alert(rtagName.test("<:>"));
//打印<table ,table
alert(rtagName.exec("<table></table>"));
//<legend,legend
alert(rtagName.exec("<legend></legend>"));
//[1,<filedSet>,<filedSet/>]
alert(wrapMap[rtagName.exec("<legend></legend>")[1]]);
//打印<filedset>
alert(wrapMap[rtagName.exec("<legend></legend>")[1]][1]);
正则表达式测试4:

var reg1=/Windows(?!95|98|NT|2000)/gi;
//可以匹配Windows,打印Windows
alert(reg1.exec("Windows4"));
//因为这后面有g,表示全局查找,通过打印RegExp的lastIndex就可以知道第一个匹配到的是第一个<字符,第二次匹配到的是结束标签的<字符!
//打印1,19
var rxhtmlTag1 = /<(?!area|br|col|embed|hr|img|input|link|meta|param)/gi;
var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
alert(rxhtmlTag1.exec("<table>I am testing</table>"));
alert(rxhtmlTag1.lastIndex);
alert(rxhtmlTag1.exec("<area>I am testing</area>"));
alert(rxhtmlTag1.lastIndex);
//下面测试rxhtmlTag正则表达式,下面就是null
alert(rxhtmlTag.exec("<table></table>"));
其它正则表达式测试:

(<span style="color:#ff0000;">?=pattern):</span>正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
<span style="color:#ff0000;">(?:pattern):</span>匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
(<span style="color:#ff0000;">?<=pattern)</span>:反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能
匹配“3.1Windows”中的“Windows”。
<span style="color:#ff0000;">(?<!pattern):</span>反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。

 

<pre name="code" class="html">

                
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值