【jQuery源码】select方法

  1 /**
  2  * select方法是Sizzle选择器包的核心方法之一,其主要完成下列任务:
  3  * 1、调用tokenize方法完成对选择器的解析
  4  * 2、对于没有初始集合(即seed没有赋值)且是单一块选择器(即选择器字符串中没有逗号),
  5  *    完成下列事项:
  6  *    1) 对于首选择器是ID类型且context是document的,则直接获取对象替代传入的context对象
  7  *    2) 若选择器是单一选择器,且是id、class、tag类型的,则直接获取并返回匹配的DOM元素
  8  *    3) 获取最后一个id、class、tag类型选择器的匹配DOM元素赋值给初始集合(即seed变量)
  9  * 3、通过调用compile方法获取“预编译”代码并执行,获取并返回匹配的DOM元素
 10  *
 11  * @param selector 已去掉头尾空白的选择器字符串
 12  * @param context 执行匹配的最初的上下文(即DOM元素集合)。若context没有赋值,则取document。
 13  * @param results 已匹配出的部分最终结果。若results没有赋值,则赋予空数组。
 14  * @param seed 初始集合
 15  */
 16 select = Sizzle.select = function( selector, context, results, seed ) {
 17     var i, tokens, token, type, find,
 18         compiled = typeof selector === "function" && selector,
 19         //在没有seed的时候,调用tokensize方法进行词法解析,结果放在match中
 20         //seed - 种子合集(搜索器搜到符合条件的标签),放入到这个初始集合seed中
 21         match = !seed && tokenize( (selector = compiled.selector || selector) );
 22
 23     results = results || [];
 24
 25     // Try to minimize operations if there is no seed and only one group
 26     //只有一组选择器,也就是选择器中没有逗号
 27     if ( match.length === 1 ) {
 28
 29         // Take a shortcut and set the context if the root selector is an ID
 30         //创建一个新的集合赋给tokens,确保原有集合不被更改
 31         tokens = match[0] = match[0].slice( 0 );
 32         /*
 33              * 若选择器是以id类型开始,且第二个是关系符(即+~>或空格),
 34              * 则获取id所属对象作为context继续完成后续的匹配
 35              *
 36              * 此处的条件判断依次为:
 37              * tokens.length > 2 :若tokens有两个以上的选择器
 38              * (token = tokens[0]).type === "ID" :第一个选择器的类型为ID(即以#开头的),
 39              * support.getById :支持getElementById函数
 40              * context.nodeType === 9 :context对象是document
 41              * documentIsHTML :当前处理的是HTML代码
 42              * Expr.relative[tokens[1].type] :第二个tokens元素是一个关系(即+~>或空格)
 43              * 在满足上面所有条件的情况下,执行if内的语句体
 44         */
 45         if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
 46                 support.getById && context.nodeType === 9 && documentIsHTML &&
 47                 Expr.relative[ tokens[1].type ] ) {
 48
 49             //查找id为matches[1]的元素
 50             context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
 51             if ( !context ) {
 52                 return results;
 53
 54             // Precompiled matchers will still verify ancestry, so step up a level
 55             } else if ( compiled ) {
 56                 context = context.parentNode;
 57             }
 58
 59             //去掉selector中第一个选择器
 60             selector = selector.slice( tokens.shift().value.length );
 61         }
 62
 63         // Fetch a seed set for right-to-left matching
 64         //其中: "needsContext"= new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
 65         //即是表示如果没有一些结构伪类,这些是需要用另一种方式过滤,在之后文章再详细剖析。
 66         //那么就从最后一条规则开始,先找出seed集合
 67         i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
 68         while ( i-- ) {
 69             token = tokens[i];
 70
 71             // Abort if we hit a combinator
 72             //如果遇到了关系选择器则终止循环,> + ~ 空
 73             if ( Expr.relative[ (type = token.type) ] ) {
 74                 break;
 75             }
 76             /*
 77                 先看看有没有搜索器find,搜索器就是浏览器一些原生的取DOM接口,简单的表述就是以下对象了
 78                 Expr.find = {
 79                     ‘ID‘    : context.getElementById,
 80                     ‘CLASS‘ : context.getElementsByClassName,
 81                     ‘NAME‘  : context.getElementsByName,
 82                     ‘TAG‘   : context.getElementsByTagName
 83                 }
 84             */
 85             if ( (find = Expr.find[ type ]) ) {
 86                 // Search, expanding context for leading sibling combinators
 87                 // 尝试一下能否通过这个搜索器搜到符合条件的初始集合seed
 88                 if ( (seed = find(
 89                     token.matches[0].replace( runescape, funescape ),
 90                     rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
 91                 )) ) {
 92
 93                     // If seed is empty or no tokens remain, we can return early
 94                     //删除这条标签
 95                     tokens.splice( i, 1 );
 96                     selector = seed.length && toSelector( tokens );
 97                     //若当前选择器是否为空,把seed推入results,返回结果
 98                     if ( !selector ) {
 99                         push.apply( results, seed );
100                         return results;
101                     }
102                     //已经找到了符合条件的seed集合,此时前边还有其他规则,跳出去
103                     break;
104                 }
105             }
106         }
107     }
108
109     // Compile and execute a filtering function if one is not provided
110     // Provide `match` to avoid retokenization if we modified the selector above
111     ( compiled || compile( selector, match ) )(
112         seed,
113         context,
114         !documentIsHTML,
115         results,
116         rsibling.test( selector ) && testContext( context.parentNode ) || context
117     );
118     return results;
119 };
时间: 2024-08-07 20:50:56

【jQuery源码】select方法的相关文章

jquery源码之工具方法

jQuery 作为时下前端的"霸主".它的强大已毋庸置疑.简洁,效率,优雅,易用等优点让人很容易对它珍爱有加. 作为js的小菜,为了提升自我等级,根据各大神博客精辟的解析,硬啃了jQuery源码.在此,并不是要解析啥源码啥的(也没到那个级别哈),读书笔记,仅此而已. 所谓磨刀不误砍柴功,jQuery在大展神通之前也做了许多准备工作.比如说他的一些工具方法: 首当其冲的是他的继承扩展方法: jQuery.extend 其实也不是传统意义的继承,说mixin可能更恰当一些. // 首先看看

十七.jQuery源码解析之入口方法Sizzle(1)

函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: 1.解析选择器表达式,解析出块表达式和关系符. 2.如果存在位置伪类,则从左向右查找: a.查找第一个块表达式匹配的元素集合,得到第一个上下文元素集合. b.遍历剩余的块表达式和块间关系符,不断缩小上下文元素集合. 3.否则从右向左查找: a.查找最后一个块表达式匹配的元素集合,得到候选集,映射集

jQuery源码学习5——工具方法之attr parents sibling clean

(1).attr attr: function(elem, name, value){ var fix = { "for": "htmlFor", "class": "className", "float": "cssFloat", innerHTML: "innerHTML", className: "className" }; if ( fix

jQuery源码学习3——工具方法篇

基本工具方法结构如下: jQuery.extend({ init:function(){}, each:function(){}, className:{ add:function(){}, remove:function(){}, has:function(){}, }, swap:function(){}, css:function(){}, curCSS:function(){}, clean:function(){}, expr:{}, token:[], find:function()

jQuery源码解析(jQuery对象的实例属性和方法)

1.记录版本号 以及 修正constructor指向 jquery: core_version, constructor: jQuery, 因为jQuery.prototype={ ... } 这种写法将自动生成的jQuery.prototype.constructor属性覆盖删除,所以需要重新修正(指向其构造函数 jQuery).2.init() 初始化方法: init()方法最终返回的是this -jQuery(其实是jQuery.prototype.init)方法的实例对象. 实例对象继承

jquery源码学习(二)sizzle部分 【转】

一,sizzle的基本原理 sizzle是jquery选择器引擎模块的名称,早在1.3版本就独立出来,并且被许多其他的js库当做默认的选择器引擎.首先,sizzle最大的特点就是快.那么为什么sizzle当时其他引擎都快了,因为当时其他的引擎都是按照从左到右逐个匹配的方式来进行查找的,而sizzle刚好相反是从右到左找的. 举个简单的例子 “.a .b .c”来说明为什么sizzle比较快.这个例子如果按照从左到右的顺序查找,很明显需要三次遍历过程才能结束,即先在document中查找.a,然后

jQuery源码学习笔记五 六 七 八 转

jQuery源码学习笔记五 六 七 八 转 Js代码   <p>在正式深入jQuery的核心功能选择器之前,还有一些方法,基本都是数组方法,用于遴选更具体的需求,如获得某个元素的所有祖选元素啦,等等.接着是其缓存机制data.</p> <pre class="brush:javascript;gutter:false;toolbar:false"> //@author  司徒正美|なさみ|cheng http://www.cnblogs.com/ru

jQuery源码之 empty与html(&#39;&#39;)的区别

empty: function() { var elem, i = 0; for ( ; (elem = this[i]) != null; i++ ) { // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { //循环清除Data数据 jQuery.cleanData( getAll( elem, false ) ); } // 移除child while ( elem.firstChild

jquery源码学习笔记(一)jQuery的无new构建

本人是一名.net程序员..... 你一个.net coder 看什么jQuery 源码啊? 原因吗,很简单.技多不压身吗(麻蛋,前端工作好高...羡慕). 我一直都很喜欢JavaScript,废话不多说了,直接切入正题. 最近看了好几篇jQuery 源码的文章,对于jQuery的无new构建  很是不解. 查了很多资料,总算是搞明白了. jQuery的无new构建 jQuery框架的核心就是从HTML文档中匹配元素并对其执行操作. 回想一下使用 jQuery 的时候,实例化一个 jQuery

五.jQuery源码解析之jQuery.extend(),jQuery.fn.extend()

给jQuery做过扩展或者制作过jQuery插件的人这两个方法东西可能不陌生.jQuery.extend([deep],target,object1,,object2...[objectN]) jQuery.fn.extend([deep],target,object1,,object2...[objectN])这两个属性都是用于合并两个或多个对象的属性到target对象.deep是布尔值,表示是否进行深度合并,默认是false,不执行深度合并.通过这种方式可以在jQuery或jQuery.fn