选择器对节点去重的处理
由于存在并联选择器,因此就算是从右到左过滤结果集,还是存在去重问题。排序问题产说了,以前JK已经给出非常逆天的算法。现在看一下去重问题。其实你们可以看成是一个纯粹的数组去重问题。难度在于速度。因此mootools搞出slickspeed这东西,引发了速度竞赛。现在让我们看看几个去重函数的实现了。
var unique = function(array) {
var ret = [];
o:for(var i = 0, n = array.length; i < n; i++) {
for(var x = i + 1 ; x < n; x++) {
if(array[x] === array[i])
continue o;
}
ret.push(array[i]);
}
return ret;
}
这是早期mass Framework的方案,不打乱顺序的
function uniq(array){
var ret = [],ri = 0
array = array.sort();
ret[ri] = array[0];
for(var j = 1, n = array.length; j < n; j++){
if(ret[ri] !== array[j]){
ret[++ri] = array[j]
}
}
return ret;
}
这是打乱顺序的。
/* 快速除重,相对于ArrayH.unique,为了效率,牺了代码量与严谨性。如果数组里有不可添加属性的对象,则会抛错.
* @method quicklyUnique
* @static
* @param {array} arr 待处理数组
* @return {array} 返回除重后的新数组
*/
quicklyUnique: function(arr) {
var strs = {},
numAndBls = {},
objs = [],
hasNull,
hasUndefined,
ret = [];
for (var i = 0, len = arr.length; i < len; i++) {
var oI = arr[i];
if (oI === null) {
if (!hasNull) {
hasNull = true;
ret.push(oI);
}
continue;
}
if (oI === undefined) {
if (!hasUndefined) {
hasUndefined = true;
ret.push(oI);
}
continue;
}
var type = typeof oI;
switch (type) {
case 'object':
case 'function':
if (!oI.__4QuicklyUnique) {
oI.__4QuicklyUnique = true;
ret.push(oI);
objs.push(oI);
}
break;
case 'string':
if (!strs[oI]) {
ret.push(oI);
strs[oI] = true;
}
default:
if (!numAndBls[oI]) {
ret.push(oI);
numAndBls[oI] = true;
}
break;
}
}
for (i = 0; oI = objs[i++];) {
if (oI instanceof Object) {
delete oI.__4QuicklyUnique;
} else {
oI.__4QuicklyUnique = undefined;
}
}
return ret;
},
这是qwrap框架提供的方案,利用经典的hash去重法,但这要对对象类型的元素做些手段,因此它只是候选放案。像网上那些流行的普通hash去重法更是经不起推敲。
unique: function(arr) {
var rlt = [],
oI = null,
indexOf = Array.indexOf || ArrayH.indexOf;
for (var i = 0, len = arr.length; i < len; i++) {
if (indexOf(rlt, oI = arr[i]) < 0) {
rlt.push(oI);
}
}
return rlt;
},
这是qwrap现时的方案,运用原生Array.prototype.indexOf,不支持需要自己做个轮子。
unique: function ( target ) {
var ret = [], n = target.length, i, j;
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++)
if (target[i] === target[j])
j = ++i;
ret.push(target[i]);
}
return ret;
},
这是mass Framework正在采用的方案,由群里的abcd提供。
Sizzle.uniqueSort = function( results ) {
if ( sortOrder ) {
hasDuplicate = baseHasDuplicate;
results.sort( sortOrder );
if ( hasDuplicate ) {
for ( var i = 1; i < results.length; i++ ) {
if ( results[i] === results[ i - 1 ] ) {
results.splice( i--, 1 );
}
}
}
}
return results;
};
这是 jQuery 1.7 前的方案,直接在原数组上操作,如果数组很大,会容易搞死IE6。由于处理的是节点,要保持像querySelectorAll那样的效果,需要按DOM树出现顺序重排。
Sizzle.uniqueSort = function( results ) {
var elem,
i = 1;
hasDuplicate = baseHasDuplicate;
results.sort( sortOrder );
if ( hasDuplicate ) {
for ( ; (elem = results[i]); i++ ) {
if ( elem === results[ i - 1 ] ) {
results.splice( i--, 1 );
}
}
}
return results;
};
jquery1.8的实现,它不再访问数组的 length 属性,提高了运行效率。每次以 elem = results[i] 赋值后是否存在为循环判定条件。
Sizzle.uniqueSort = function( results ) {
var elem,
duplicates = [],
i = 1,
j = 0;
hasDuplicate = baseHasDuplicate;
results.sort( sortOrder );
if ( hasDuplicate ) {
for ( ; (elem = results[i]); i++ ) {
if ( elem === results[ i - 1 ] ) {
j = duplicates.push( i );
}
}
while ( j-- ) {
results.splice( duplicates[ j ], 1 );
}
}
return results;
};
jquery1.83的实现,它是先保持了索引值,然后从后面开始删除,避免数组索引的改动导致删除错误。
但明显jquery.unique不能用于普通的数组去重。因此在mass Framework它们是不相干的两个函数。
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
浙公网安备 33010602011771号