由于存在并联选择器,因此就算是从右到左过滤结果集,还是存在去重问题。排序问题产说了,以前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它们是不相干的两个函数。