jQuery源码分析之实例find和filter方法的区别七问
问题1:jQuery.filter的源码是什么?
jQuery.filter = function( expr, elems, not ) {var elem = elems[ 0 ];//如果含有第三个参数表示选择不满足特定条件的结果!if ( not ) {expr = ":not(" + expr + ")";}return elems.length === 1 && elem.nodeType === 1 ?//如果选择集合只有一个元素,调用matchesSelector,否则调用matches方法!jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {return elem.nodeType === 1;}));//很显然返回的是集合!
};
很显然返回的是对象数组,同时第三个参数表示是否取反,grep第三个参数也是取反功能!
问题2:jQuery.filter调用方式有那些?
在prevAll,nextAll,siblings中调用
ret = jQuery.filter( selector, ret );
例子:
<div class="father" id="father" style="background-color:red;height:400px;background-color:#ccc;">
</div> <div class="father" style="background-color:red;height:400px;background-color:#ccc;">
</div>
JS部分
//获取集合$("div")中满足class为father的元素var result=jQuery.filter(".father",$("div"));console.log(result);//打印[div#father.father, div.father]
因为jQuery.filter的第三个参数表示 是否取反,那么我们如何把它设置为true表示取反,也就是不满足selector的元素的集合
//获取集合$("div")中满足class不为father的元素var result=jQuery.filter(".father",$("div"),true);console.log(result);//打印[]
通过源码很容易看到
if ( not ) {expr = ":not(" + expr + ")";//第三个参数表示对选择器进行取反,也就是添加:not!}
注意:jQuery.filter是对元素的集合进行筛选,所以返回的数组元素本来就在筛选之前的集合中!
问题3:上面是jQuery.filter方法,那么filter实例方法如何?
学习实例filter方法之前,我们先看看winnow方法
他的调用方式有以下
实例filter方法中:
winnow(this, selector || [], false)
实例not方法中:
winnow(this, selector || [], true)
实例is方法中:
winnow(this,
// If this is a positional/relative selector, check membership in the returned set
// so $("p:first").is("p:last") won't return true for a doc with two "p".typeof selector === "string" && rneedsContext.test( selector ) ?jQuery( selector ) :selector || [],false)
现在我们看看winnow方法的源码:
function winnow( elements, qualifier, not ) {if ( jQuery.isFunction( qualifier ) ) {return jQuery.grep( elements, function( elem, i ) {/* jshint -W018 */return !!qualifier.call( elem, i, elem ) !== not;});}if ( qualifier.nodeType ) {return jQuery.grep( elements, function( elem ) {return ( elem === qualifier ) !== not;});}if ( typeof qualifier === "string" ) {if ( risSimple.test( qualifier ) ) {return jQuery.filter( qualifier, elements, not );}qualifier = jQuery.filter( qualifier, elements );}return jQuery.grep( elements, function( elem ) {return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;});
}
如果是实例not,filter方法(传入字符串),那么执行下面的逻辑
//在filter和not实例方法中,执行这里的逻辑if ( typeof qualifier === "string" ) {//var risSimple = /^.[^:#\[\.,]*$/;//如果是普通的选择器,那么我们用这个selector对数组进行筛选//对于not方法来说传入的true表示取反,而is实例方法不需要取反!if ( risSimple.test( qualifier ) ) {return jQuery.filter( qualifier, elements, not );}qualifier = jQuery.filter( qualifier, elements );}
所以还是调用jQuery.filter对 调用对象进行筛选,所以返回的对象 都是调用对象的一个子集!
如果是is方法,is()函数用于判断当前jQuery对象所匹配的元素是否符合指定的表达式。 只要其中有至少一个元素符合该表达式就返回true,否则返回false。这里的表达式包括:选择器(字符串)、DOM元素(Element)、jQuery对象、函数。 注意:is,not,filter方法都是可以传入字符串,DOM元素,jQuery对象,函数的,因为他们内部都是调用了winnow方法!
问题4:既然is,not,filter方法可以传入DOM,jQuery对象,函数对象,可以举例吗?
<div class="father" id="father" style="background-color:red;height:400px;background-color:#ccc;">
</div> <div class="father" style="background-color:red;height:400px;background-color:#ccc;">
</div>
我们给filter传入DOM
//我们知道is,not,filter都是可以传入DOM对象的var result=$("div").filter($("#father")[0]);console.log(result);//打印[div#father.father, prevObject: jQuery.fn.init[2], context: document]
传入DOM,表示筛选指定的DOM元素,这时候返回的是含有指定DOM的jQuery对象
给is方法传入DOM
//我们知道is,not,filter都是可以传入DOM对象的var result=$("div").is($("#father")[0]);console.log(result);//打印true!
这时候打印true,只要调用对象含有参数对象,那么返回 布尔值true!
//我们知道is,not,filter都是可以传入DOM对象的var result=$("div").not($("#father")[0]);console.log(result);//打印[div.father, prevObject: jQuery.fn.init[2], context: document]!
这时候打印第二个div元素,表示返回除了指定元素外的其它的元素! 要注意:is方法返回的是布尔值!
传入的是DOM,那么在winnow函数中执行下面的逻辑:
if ( qualifier.nodeType ) {//调用了grep方法,该方法为每一个元素调用指定的函数,如果该函数返回true//那么把该元素放入结果集合中(grep第三个参数在这里是false!)。return jQuery.grep( elements, function( elem ) {return ( elem === qualifier ) !== not;});}
如果是is或者filter方法,那么not是false,表示不用取反,这时候在上面这段代码中就是返回elem===qualifier的对象,也就是传入的参数对象,不同之处在于is已经转化为布尔值了 ! jQuery.grep的作用在于:选择调用指定函数后返回值是我们期望内向的元素(如果第三个参数是false表示返回调用函数返回true的元素,如果第三个参数是true表示返回调用函数的结果是false的元素)。如果是not方法,那么返回调用对象中不是指定元素的DOM元素!
问题5:is,not,filter方法中可以传入jQuery对象?
HTML还是和上面的例子一样
not实例方法
//我们知道is,not,filter都是可以传入jQuery对象的var result=$("div").not($("#father"));console.log(result);//打印[div.father, prevObject: jQuery.fn.init[2], context: document]
is方法
//我们知道is,not,filter都是可以传入jQuery对象的var result=$("div").is($("#father"));console.log(result);//打印true
filter实例方法
//我们知道is,not,filter都是可以传入jQuery对象的var result=$("div").filter($("#father"));console.log(result);//打印[div#father.father, prevObject: jQuery.fn.init[2], context: document]
这时候在winnow方法中执行下面的代码逻辑:
return jQuery.grep( elements, function( elem ) {return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;});
这时候jQuery.grep第三个参数是false,表示返回执行指定函数后为true的DOM元素组成的数组。对于is,filter方法来说,not是false,那么表示,如果当前元素在参数也就是qualifier所在的集合中就会返回! 反过来想想,只要调用对象在参数集合中都会返回!如果是not实例方法,不在参数jQuery对象中的调用对象的所有的DOM都会返回!
问题6:is,not,filter方法中可以传入函数对象?
filter传入函数对象
//我们知道is,not,filter都是可以传入函数对象的var result=$("div").filter(function(index,elem){if(elem.id==="father"){return false;//不需要放入结果集合中就直接返回false,所以id=father元素不会在结果集合中}return true;//需要返回就return true!});//打印[div.father, prevObject: jQuery.fn.init[2], context: document]console.log(result);
注意:传入的回调函数情况下,回调函数中第一个参数是下标,第二个参数是元素!
is方法传入函数:
//我们知道is,not,filter都是可以传入函数对象的var result=$("div").is(function(index,elem){if(elem.id==="father"){return false;//不需要放入结果集合中就直接返回false,所以id=father元素不会在结果集合中}return true;//需要返回就return true!});//打印true,因为对于第一个div元素执行函数返回了true!console.log(result);
只要有一个函数调用后返回了true,那么结果就是true!
not方法传入函数:
//我们知道is,not,filter都是可以传入函数对象的var result=$("div").not(function(index,elem){if(elem.id==="father"){return false;//not方法如果返回false那么会在结果集合中!}return true;//返回true不再结果集合中!});//打印[div#father.father, prevObject: jQuery.fn.init[2], context: document]console.log(result);
not方法传入函数,只要返回false就会在结果集合中,返回true不会在结果集合中!执行的代码逻辑是
if ( jQuery.isFunction( qualifier ) ) {//如果是函数参数,那么我们让每一个元素执行指定的函数!return jQuery.grep( elements, function( elem, i ) {/* jshint -W018 */return !!qualifier.call( elem, i, elem ) !== not;});}
实例not方法源码
not: function( selector ) {return this.pushStack( winnow(this, selector || [], true) );}
实例is方法源码
is: function( selector ) {return !!winnow(this,// If this is a positional/relative selector, check membership in the returned set// so $("p:first").is("p:last") won't return true for a doc with two "p".typeof selector === "string" && rneedsContext.test( selector ) ?jQuery( selector ) :selector || [],false).length;}
实例filter源码
filter: function( selector ) {return this.pushStack( winnow(this, selector || [], false) );//通过winnow方法选择成功过后我们进行入栈,返回是jQuery对象!}
问题7:我们不是讲实例filter方法和实例find方法的差别吗?看下面的差别?
首先来讨论一下find实例方法的作用:find()函数用于选取每个匹配元素的 符合指定表达式的后代元素,并以jQuery对象的形式返回。这里的表达式包括:选择器(字符串)、DOM元素(Element)、jQuery对象。
从这里你就会看到:虽然find方法和其它的方法一样可以传入DOM,jQuery,字符串(find方法无法传入函数),但是find方法返回的是调用对象满足指定选择器的子元素,而filter方法返回的是调用对象的一个集合!
jQuery.find = Sizzle;
我们知道最终还是调用了Sizzle的相关方法
如果我们传入了DOM或者jQuery对象
var i,ret = [],self = this,len = self.length;//如果find方法传入DOM,jQuery等执行这里的逻辑if ( typeof selector !== "string" ) {//所以如果是DOM,jQuery最终还是调用了filter实例方法//不过,这时候成了判断调用对象是否包含参数对象,如果包含就直接返回!//记住:这时候返回的是参数对象,参数对象扮演了子元素的角色return this.pushStack( jQuery( selector ).filter(function() {for ( i = 0; i < len; i++ ) {if ( jQuery.contains( self[ i ], this ) ) {return true;}}}) );}
通过上面的代码,虽然find方法不能传入函数,但是如果传入了DOM/jQuery对象,那么参数扮演的就是子元素的角色, 该方法返回的是子元素!
var result=$("div").find($("#father"));//打印[div#father.father, prevObject: jQuery.fn.init[2], context: document]//返回的是子元素!console.log(result);
判断$("div")这个调用对象集合中是否有子元素的id=father,如果有,那么返回!
如果我们传入了字符串的选择器:
//如果是字符串对象的选择器,调用Sizzle,把所有的结果放入ret集合中!for ( i = 0; i < len; i++ ) {jQuery.find( selector, self[ i ], ret );}// Needed because $( selector, context ) becomes $( context ).find( selector )//如果调用对象的DOM对象有多个,那么调用jQuery.unique来对集合进行去重,如果只有一个DOM不用去重!//这时候返回的ret已经是jQuery对象了!ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );//这时候要对selector进行更新,$("div").find(".name")那么返回的对象就是通过双重选择来完成的//变成("div .name")ret.selector = this.selector ? this.selector + " " + selector : selector;return ret;
注意:通过find方法返回的是jQuery对象。我们看看下面的代码:
ret.selector = this.selector ? this.selector + " " + selector : selector;
通过下面的代码:
var result=$("div").find($("#father"));//打印[div#father.father, prevObject: jQuery.fn.init[2], context: document]//返回的是子元素!console.log(result);
这时候返回的对象result的selector是"div#father"也就是双重选择的结果了!
总结:
(1)filter方法把this对象也就是调用对象传入winnow函数,同时把参数也就是选择器也传入winnow,在winnow里面调用jQuery.filter按照指定的选择器进行筛选,返回的是调 用对象个部分元素
(2)对于find方法,如果传入的对象不是string,如DOM对象等,那么通过contains或者compareDocumentPosition来判断。其中参数对象扮演的角色就是子元素,只要有调用对象包含着这个参数对象,就会把参数对象保存起来,所以该方法保存的是子元素!
(3)区别:filter返回调用对象自己,find方法返回子元素
jQuery源码分析之实例find和filter方法的区别七问相关推荐
- jQuery源码分析之removeAttr方法和attr方法
jQuery.removeAttr函数源码测试: <input type="radio" checked/> var rnotwhite = (/\S+/g); var ...
- jQuery源码分析-each函数
本文部分截取自且行且思 jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 复制代码代码 /*! * jQuer ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- [转] jQuery源码分析-如何做jQuery源码分析
jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...
- [转]jQuery源码分析系列
文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...
- jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/unde
10.4 .bind() .one() 10.4.1 如何使用 .bind( eventType, [eventData], handler(eventObject) ) 在匹配的元素上绑 ...
- jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/undelegate
Js代码 作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 后文预告:封装事件对象 便 ...
- Envoy 源码分析--network L4 filter manager
目录 Envoy 源码分析--network L4 filter manager FilterManagerImpl addWriteFilter addReadFilter addFilter in ...
- jQuery源码分析系列:属性操作
属性操作 1.6.1相对1.5.x最大的改进,莫过于对属性.attr()的重写了.在1.6.1中,将.attr()一分为二: .attr()..prop(),这是一个令人困惑的变更,也是一个破坏性的升 ...
最新文章
- im即时通讯源码_IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)
- NeHe教程Qt实现——lesson17
- spring boot + spring cloud 基础架构设计
- Spring容器初始化和bean创建过程
- ActionBar设置自定义setCustomView()留有空白的问题
- 电子商务人们广泛使用计算机,电子商务基础——PPT课件
- 计算机考试演示文稿模板,2018职称计算机考试PowerPoint习题10
- Mongodb系列:初识Mongodb
- php数组去重复数据的小例子
- opencv将图像转换成二维数组再将数组数据传给新图像
- 软件各项会议评审意见模版
- 接口测试搭建之JMeter接口测试与SoapUI接口测试
- 正则表达式同时匹配中英文及常用正则表达式
- socket服务器主动下发消息,socket服务器主动发送消息给客户端
- CodeBook 可以自定义字符集的密码本
- linux连接库参数-l,gcc编译时,什么时候需要用-l参数指明连接库?
- 超级好用的电脑截图翻译软件你值得拥有!
- 笔记本无线上网卡的种类
- 七牛云 转码_七牛云4:上传后自动添加水印、视频转码
- ibm tivoli_IBM Tivoli Directory Server中的安全复制