}
newSelector = groups.join(",");
// Expand context for sibling selectors
newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
}
if (newSelector) {
try {
push.apply(results, newContext.querySelectorAll(newSelector));
return results;
} catch(qsaError) {} finally {
if (nid === expando) {
context.removeAttribute("id");
}
}
}
}
}
}
// All others,select 函数和 tokenize 函数后文再谈
return select(selector.replace(rtrim, "$1"), context, results, seed);
}
整个分析过程由于要考虑各种因素,包括效率和浏览器兼容性等,所以看起来非常长,但是逻辑一点都不难:先判断 selector 是否是非 string,然后正则 rquickExpr 对 selector 进行匹配,获得数组依次考虑 id、tagName 和 class 情况,这些都很简单,都是单一的选择,一般用浏览器自带的函数 getElement 即可解决。遇到复杂一点的,比如
div div.show p,先考虑 querySelectorAll 函数是否支持,然后考虑浏览器兼容 IE<8。若不支持,即交给 select 函数(下章)。Sizzle 的优势
Sizzle 使用的是从右向左的选择方式,这种方式效率更高。
浏览器在处理 html 的时候,先生成一个 DOM tree,解析完 css 之后,然后更加 css 和 DOM tess 生成一个 render tree。render tree 用于渲染,不是一一对应,如
display:none 的 DOM 就不会出现在 render tree 中。如果从左到右的匹配方式,
div div.show p, 找到 div 节点,
从 1 的子节点中找到 div 且 class 为 show 的 DOM,找不到则返回上一步
从 2 的子节点中找到 p 元素,找不到则返回上一步
如果有一步找不到,向上回溯,直到遍历所有的 div,效率很低。
如果从右到左的方式,
先匹配到所有的 p 节点,
对 1 中的结果注意判断,若其父节点顺序出现
div.show 和 div,则保留,否则丢弃因为子节点可以有若干个,而父节点只有一个,故从右向左的方式效率很高。
衍生的函数
jQuery.fn.pushStack
jQuery.fn.pushStack是一个类似于
jQuery.merge 的函数,它接受一个参数,把该参数(数组)合并到一个 jQuery 对象中并返回,源码如下:
jQuery.fn.pushStack = function (elems) { // Build a new jQuery matched element set
var ret = jQuery.merge(this.constructor(), elems);
// Add the old object onto the stack (as a reference)










