jQuery源码分析之contains函数

jQuery,.contains底层调用的方法来自于JS的contains方法和compareDocumentPosition方法

测试例子:

//打印true
alert(document.getElementById("sec").ownerDocument===document);
//打印[object HTMLDocument]
alert(document.getElementById("sec").ownerDocument);

测试代码2:

//打印true
alert(document.getElementById("sec").ownerDocument===document);
//打印false,getElementsByTagName("body")[0]则返回true
alert(document.getElementsByTagName("body").ownerDocument===document);
//打印true
alert(document.getElementsByTagName("body")[0].ownerDocument===document);
//打印undefined,因为是NodeList,不是Element元素
alert(document.getElementsByTagName("body").ownerDocument);
//不是Element对象,直接返回undefined
alert(document.getElementsByTagName("p").ownerDocument);
//打印[object Window]
alert(document.defaultView);
//打印undefined
alert(document.getElementById("sec").defaultView);
//打印undefined,document对象才有defaultView和documentElement
alert(document.getElementById("sec").documentElement);

从这个例子中你要弄清楚,ownerDocument是Element元素的专利,而NodeList等没有ownerDocument属性;同时defaultView是document的专利,返回的是window对象。对于不同的浏览器可能用document.defaultView||document.parentWindow||window!

测试代码3:

//rnative = /^[^{]+\{\s*\[native \w/
//[^{]表示除了左大括号的任何字符
//var docElem = window.document.documentElement;
//打印[object HTMLHtmlElement]
//alert( window.document.documentElement);
//alert( window.document.documentElement.compareDocumentPosition);打印function compareDocumentPosition(){[native code]}
//alert( window.document.documentElement.contains);打印function contains(){[native code]}

从这个例子你应该明白,jQuery的contains判断是否有JS原生的contains和compareDocument方法用的是正则表达式的!

			<div id="n1">
			<p id="n2">
				<span id="n3">CodePlayer</span>
			</p>
			</div>
		       <p id="n4">专注于编程开发技术分享</p>

JS部分

			    //n1虽然包含span元素(n3),但变量span是NodeList对象,不是Element类型。
				alert( $.contains(n1, $("span")) ); // false
				//NodeList的parentNode是undefined,打印undefined
				alert(span.parentNode);
				//jQuery对象也没有parentNode,parentNode是JS原生的属性
				alert($("#n1").parentNode);
contains方法的第二个参数必须是Element对象,而 不能是jQuery对象或者NodeList对象!

contains方法:

      hasCompare = rnative.test( docElem.compareDocumentPosition );
	// Element contains another
	// Purposefully does not implement inclusive descendent
	// As in, an element does not contain itself
	//contains函数
	//如果正则表达式通过表示浏览器支持compareDocumentPosition,如果不支持那么继续判断JS原生的contains函数
	contains = hasCompare || rnative.test( docElem.contains ) ?
		function( a, b ) {
		//如果a元素是document对象,那么获取documentElement,否则保存a对象即可
			var adown = a.nodeType === 9 ? a.documentElement : a,
		//如果b不是空,那么获取b元素的parentNode对象
				bup = b && b.parentNode;
//(1)如果b元素的父元素是a元素,那么返回true,否则继续下一步判断
//(2)如果b的父元素存在,但是不是a元素,而且父元素已经是docmentElement也就是html元素,如:alert(document.getElementsByTagName("body")[0].parentNode.nodeType);返回1
			//注意:这里必须要求b的parentNode是元素类型,NodeList等类型直接返回false,见上例子:
			return a === bup || !!( bup && bup.nodeType === 1 && (
				adown.contains ?
				//如果contains存在,调用contains,也就是a包含了b元素的父亲
					adown.contains( bup ) :
				  //如果不存在contains方法,那么直接调用compareDocumentPosition方法就可以了!
					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
			));
		} :
		//如果不存在compareDocumentPosition也不存在contains方法,那么直接取出b的parentNode
		//比较parentNode和a是否相等,如果相等就返回true
		function( a, b ) {
			if ( b ) {
				while ( (b = b.parentNode) ) {
					if ( b === a ) {
						return true;
					}
				}
			}
			return false;
		};

如果是具有原生的compareDocumentPosition或者contains我们就调用下面的逻辑:

            function( a, b ) {
			var adown = a.nodeType === 9 ? a.documentElement : a,
				bup = b && b.parentNode;
			return a === bup || !!( bup && bup.nodeType === 1 && (
				adown.contains ?
					adown.contains( bup ) :
					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16//验证被包含关系我们用&16!
			));
		} 

compareDocumentPosition还可以用于比较其它的关系:

上面的HTML,n4在n1后面

   //n4在n1后面
   var result=$('#n1')[0].compareDocumentPosition($('#n4')[0])&4;
   //打印4,所以n4在n1后面(前后是站在参数的角度上来说的,判断参数相对于调用者的位置)
   console.log(result);
上面的HTML,判断n2包含n3

   //n2包含n3
   var result=$('#n3')[0].compareDocumentPosition($('#n2')[0])&8;
   //打印8,所以n2包含n3(前后是站在参数的角度上来说的,判断参数相对于调用者的位置)
   console.log(result);
注意:compreDcoumentPositon站在参数的角度上来说的, 2表示参数居前,4表示参数居后,8表示参数包含,16表示参数被包含!

如果没有原生的方法的时候我们调用下面的逻辑

                function( a, b ) {
			if ( b ) {
				while ( (b = b.parentNode) ) {
					if ( b === a ) {
						return true;
					}
				}
			}
			return false;
		};
不管获取被包含节点的父节点,如果当前节点和父节点相同,那么我们返回true

你可能感兴趣的:(jQuery源码分析之contains函数)