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;
};