Sizzle一步步实现所有功能(一)

时间:2024-10-27 09:03:56

前提:

1.HTML5自带querySelectAll可以完全替代Sizlle,所以我们下面写的Sizzle,是不考虑QSA的。

2.作者考虑了大量兼容情况,比如黑莓4.6系统这样几乎接触不到的bug。这样学习价值不高却很费时间问题我不去考虑。主要考虑IE8,这也是Sizzle没被淘汰的最主要原因。

3.我喜欢采用var 声明每个变量,而不是一个var 声明好多变量。原因是我在一步步完善模仿的Sizzle,会有大量的修改。

4.Sizzle的原理实际很简单,真的就可以这样一句话遍历页面所有元素,对每个元素进行排除,符合的则插入到结果数组。但功能繁多,层级繁杂,难点是架构。

5.这是一篇超长的文章。

第一步:实现Sizzle('#ID),Sizzle("TAG"),Sizzle(".CLASS")

 (function( window ){

 var arr = [];
var select ;
var push = arr.push;
// http://www.w3.org/TR/css3-selectors/#whitespace
// 各种空白待穿正则字符串
var whitespace = "[\\x20\\t\\r\\n\\f]";
// 带空格选择器正则,记忆无空格选择器
var rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" );
// 快速选择器正则 ID 或者 TAG(包括*) 或者 CLASS 选择器
var rquickExpr = /^(?:#([\w-]+)|(\w+|\*)|\.([\w-]+))$/; // 浏览器代码正则
var rnative = /^[^{]+\{\s*\[native \w/; // 入口
function Sizzle( selector ){
// 清除空格
selector = selector.replace( rtrim, "$1" )
var results = [];
var match;
var matcher;
var elem;
var m;
var context = document; // 是否为最简选择器
if( match = rquickExpr.exec( selector )){
// Sizzle('#ID)
if ( (m = match[1]) ) {
elem = context.getElementById( m );
if( elem ){
results.push( elem );
}
return results; // Sizzle("TAG")
}else if( (m = match[2]) ){
push.apply( results, context.getElementsByTagName( selector ) );
return results; // Sizzle(".CLASS")
}else if( (m = match[3]) ){
// 支持getElementsByClassName
if( support.getElementsByClassName ){
push.apply( results, context.getElementsByClassName( m ) );
return results; // 不支持getElementsByClassName
}else {
// 获取遍历所有元素
// 如果元素类名与我们选择器匹配的类名相同,则插入到结果数组中
var elems = document.getElementsByTagName('*');
var pattern = new RegExp(selector.slice(1));
for(var i = 0; i<elems.length; i++) {
if(pattern.test(elems[i].className)){
results.push(elems[i])
}
}
}
}
}
return results;
}
// 版本支持变量的对外访问入口
var support = Sizzle.support = {}; // 判断是否支持getElementsByClassName
// 支持: IE<9
support.getElementsByClassName = rnative.test( document.getElementsByClassName ); // 对外入口
window.MSizzle = Sizzle; })(window)
console.log(MSizzle("#id"))
console.log(MSizzle(".class"))
console.log(MSizzle("div"))

1.rquickExpr.exec( selector )返回一个数组,exec方法返回一个数组,第0项是匹配的内容,第1项是第一个括号中记忆的内容,第2项是第一个括号中记忆的内容,依次类推。

console.log(/(1)|(2)|(3)/.exec('1')); //[ "1", "1", undefined, undefined ]
console.log(/(1)|(2)|(3)/.exec('2')); //[ "2", undefined, "2", undefined ]
console.log(/(1)|(2)|(3)/.exec('3')); //[ "3", undefined, undefined, "3" ]

2.判断浏览器是否支持某段代码的正则rnative = /^[^{]+\{\s*\[native \w/