问题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方法的区别七问相关推荐

  1. jQuery源码分析之removeAttr方法和attr方法

    jQuery.removeAttr函数源码测试: <input type="radio" checked/> var rnotwhite = (/\S+/g); var ...

  2. jQuery源码分析-each函数

    本文部分截取自且行且思 jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 复制代码代码 /*! * jQuer ...

  3. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  4. [转] jQuery源码分析-如何做jQuery源码分析

    jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...

  5. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  6. jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/unde

    10.4    .bind() .one() 10.4.1  如何使用 .bind( eventType, [eventData], handler(eventObject) )   在匹配的元素上绑 ...

  7. jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/undelegate

    Js代码   作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 后文预告:封装事件对象 便 ...

  8. Envoy 源码分析--network L4 filter manager

    目录 Envoy 源码分析--network L4 filter manager FilterManagerImpl addWriteFilter addReadFilter addFilter in ...

  9. jQuery源码分析系列:属性操作

    属性操作 1.6.1相对1.5.x最大的改进,莫过于对属性.attr()的重写了.在1.6.1中,将.attr()一分为二: .attr()..prop(),这是一个令人困惑的变更,也是一个破坏性的升 ...

最新文章

  1. im即时通讯源码_IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)
  2. NeHe教程Qt实现——lesson17
  3. spring boot + spring cloud 基础架构设计
  4. Spring容器初始化和bean创建过程
  5. ActionBar设置自定义setCustomView()留有空白的问题
  6. 电子商务人们广泛使用计算机,电子商务基础——PPT课件
  7. 计算机考试演示文稿模板,2018职称计算机考试PowerPoint习题10
  8. Mongodb系列:初识Mongodb
  9. php数组去重复数据的小例子
  10. opencv将图像转换成二维数组再将数组数据传给新图像
  11. 软件各项会议评审意见模版
  12. 接口测试搭建之JMeter接口测试与SoapUI接口测试
  13. 正则表达式同时匹配中英文及常用正则表达式
  14. socket服务器主动下发消息,socket服务器主动发送消息给客户端
  15. CodeBook 可以自定义字符集的密码本
  16. linux连接库参数-l,gcc编译时,什么时候需要用-l参数指明连接库?
  17. 超级好用的电脑截图翻译软件你值得拥有!
  18. 笔记本无线上网卡的种类
  19. 七牛云 转码_七牛云4:上传后自动添加水印、视频转码
  20. ibm tivoli_IBM Tivoli Directory Server中的安全复制

热门文章

  1. 怎么让人爆照_8招,让你用高逼格照片引爆朋友圈!
  2. vue中watch的初次监听和深度监听
  3. 【假期层次晋升计划】四点共圆、托勒密定理——2014年6月25日
  4. 数学 -- log
  5. 英语思维导图大全 非谓语(十二)
  6. 解决 js 长任务导致的页面卡顿(时间分片技术)
  7. 什么是Web 2.0
  8. 类似微信朋友圈的mysql数据库
  9. 码市:Coding 进入软件众包领域
  10. 鲁大师发布2021年半年报,哪些手机最强?