jQuery源码——find函数

24 篇文章 0 订阅
11 篇文章 0 订阅

jQuery的全局方法find()作用是对调用的jquery对象中,查找是否有满足selector的节点.

代码如下

find: function( selector ) { //在已生成的DOM中按照selector查找对应元素
		var i, l, length, n, r, ret,
			self = this;

		if ( typeof selector !== "string" ) {
			return jQuery( selector ).filter(function() { //jQuery(selector) = jQuery.init(selector) 调用filter方法,得到符合条件的新jquery对象
				for ( i = 0, l = self.length; i < l; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) { //便利self中的每一个元素,看看是不是里面有this,如果有返回true。self[i]是祖先,this是被检测的元素
						return true;
					}
				}
			});
		}

		ret = this.pushStack( "", "find", selector ); //selector拼接一下,然后添加的elem是空

		for ( i = 0, l = this.length; i < l; i++ ) { //this 是调用find的jquery对象,ret是全局jQuery对象
			length = ret.length;
			jQuery.find( selector, this[i], ret ); //这里有跑到Sizzle里面了,把结果放到ret里面.根据selector,把this[i]中符合selector的结果放到ret里面

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( n = length; n < ret.length; n++ ) { //去重,从添加位置开始,分成两截,去掉重复的部分(去掉后面的)
					for ( r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			} //每次find完了都去一下重
		}

		return ret; //最终返回结果
	},

在selector不是String的时候,调用了jquery的filter方法,过滤的条件是一个function,其中调用了contains方法。

先看看filter方法:

filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector ); //elem 是winnow(this,selector,true),把筛选出来的结果放到全局jQuery对象中
	},
关键在于winnow()方法。条件是根据不同的selector类型,调用grep方法。这个方法是在一个类数组中,根据selector找到符合要求的elems,并把结果返回

function winnow( elements, qualifier, keep ) {
        //接收的selector可以是function,条件选择器,dom元素,jquery对象
	// Can't pass null or undefined to indexOf in Firefox 4
	// Set to 0 to skip string check
	qualifier = qualifier || 0;

	if ( jQuery.isFunction( qualifier ) ) { //这里定义了selector可以是function
		return jQuery.grep(elements, function( elem, i ) { //grep函数是在elements中找到符合selector的元素。 Finds the elements of an array which satisfy a filter function。
			var retVal = !!qualifier.call( elem, i, elem ); //筛选中调用qualifier,!!用于强制类型转换为boolean
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) { //elements中遍历每一个元素,是不是等于传来的node
			return ( elem === qualifier ) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1; //检查elements,看看是不是在筛选结果中.
		});

		if ( isSimple.test( qualifier ) ) { //如果.[role=dialog]这种选择器表达式.结果会放在一个数组里面,遍历他们
			return jQuery.filter(qualifier, filtered, !keep); //elements 是qulifier了,筛选条件变成了了filtered(走qualifier.nodetype).删除重复的结果
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) { //如果qualifier是jquery元素的话,则看每一个elem是不是在qualifier中
		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; 
	});
}
grep:

grep: function( elems, callback, inv ) {
		var retVal,
			ret = [],
			i = 0,
			length = elems.length;
		inv = !!inv;

		// Go through the array, only saving the items
		// that pass the validator function
		//遍历elem,对每一个elem调用callback,如果满足条件则push
		for ( ; i < length; i++ ) {
			retVal = !!callback( elems[ i ], i );
			if ( inv !== retVal ) {
				ret.push( elems[ i ] );
			}
		}

		return ret;
	},

再看看contains方法,这个方法是引用了Sizzle的contains方法。方法如下:

var contains = Sizzle.contains = docElem.compareDocumentPosition ? //如果浏览器支持compareDocumentPosition这个方法
	function( a, b ) {
		return !!( a.compareDocumentPosition( b ) & 16 );
	} :
	docElem.contains ? //是否支持js原生的contains方法
	function( a, b ) {
		var adown = a.nodeType === 9 ? a.documentElement : a, //如果a是DocumentNode,则adown是document的元素,否则是a本身
			bup = b.parentNode;
		return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); //b有父元素,并且在adown上调用contains看看是不是有bup.这里必须要求b的parentNode是元素类型,NodeList等类型直接返回false
	} :
	function( a, b ) { //顺着dom tree往上找,看看能不能找到parent
		while ( (b = b.parentNode) ) {
			if ( b === a ) {
				return true;
			}
		}
		return false;
	};




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值