选择器对节点去重的处理

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值