JavaScript数组去重的六种实现方案与性能对比
本文汇总了JavaScript中数组去重的六种常见实现方式,涵盖基于indexOf的遍历、哈希表映射、排序后相邻比较、原型链兼容处理以及嵌套循环等方案。通过对比执行时间与内存占用,分析空间换时间策略及IE8兼容性问题,为前端开发提供实用的去重代码参考。
数组去重问题的背景与考察点
在前端开发面试中,如何去除JavaScript数组中的重复元素是一个高频考点。百度、腾讯、盛大等知名企业均曾以此为题考察候选人。这道题目看似简单,实则蕴含深意,不仅考察功能实现,更检验开发者对计算机程序执行机制的理解深度。
基于indexOf与哈希表的三种基础实现
以下是三种基于不同逻辑的去重算法实现思路:
Array.prototype.unique1 = function()
{
var n = []; //一个新的临时数组
for(var i = 0; i < this.length; i++) //遍历当前数组
{
//如果当前数组的第i已经保存进了临时数组,那么跳过,
//否则把当前项push到临时数组里面
if (n.indexOf(this[i]) == -1) n.push(this[i]);
}
return n;
}
Array.prototype.unique2 = function()
{
var n = {},r=[]; //n为hash表,r为临时数组
for(var i = 0; i < this.length; i++) //遍历当前数组
{
if (!n[this[i]]) //如果hash表中没有当前项
{
n[this[i]] = true; //存入hash表
r.push(this[i]); //把当前数组的当前项push到临时数组里面
}
}
return r;
}
Array.prototype.unique3 = function()
{
var n = [this[0]]; //结果数组
for(var i = 1; i < this.length; i++) //从第二项开始遍历
{
//如果当前数组的第i项在当前数组中第一次出现的位置不是i,
//那么表示第i项是重复的,忽略掉。否则存入结果数组
if (this.indexOf(this[i]) == i) n.push(this[i]);
}
return n;
}
第一种和第三种方法均依赖数组的indexOf方法,该方法用于查找参数在数组中首次出现的位置。由于JS引擎实现时需遍历数组直至找到目标,因此该方法存在较大的时间开销。相比之下,第二种方法采用哈希表(Hash Table)机制,将已出现的元素作为下标存入对象中。由于对象下标引用的速度远快于数组遍历搜索,因此第二种方法在效率上具有显著优势。
为了验证上述三种方法的性能差异,构建了一个测试程序:生成一个长度为10000的随机数组,并分别测试各方法的执行耗时。测试结果显示,第二种方法的速度远超其他两种。尽管第二种方法因额外创建哈希表而占用更多内存,但这正是典型的“空间换时间”策略。读者可访问相关测试页面查看具体数据。
基于排序的第四种实现方案
参考hpl大牛的思路,衍生出第四种去重方法:
Array.prototype.unique4 = function()
{
this.sort();
var re=[this[0]];
for(var i = 1; i < this.length; i++)
{
if( this[i] !== re[re.length-1])
{
re.push(this[i]);
}
}
return re;
}
该方案的核心逻辑是先对数组进行排序,随后比较相邻的两个值。排序过程调用JS原生的sort方法,推测JS引擎内部采用快速排序算法。最终测试表明,该方法的平均运行时间约为第二种方法的三倍,但明显快于第一种和第三种方法。
兼容IE8的第五种实现方案
第五种方法的实现如下:
在开发“搜索历史记录”功能时曾遇到此需求。初期使用了indexOf方法,但发现该方法仅在ECMA5标准中支持,无法兼容IE8及以下版本的浏览器。
为此,可以通过自定义函数(将方法定义在Array原型对象上)来提供兼容支持,具体实现如下:
Array.prototype.unique = function(){
var length = this.length;
if(length <= 1){
return this;
}
if(!Array.prototype.indexOf){
Array.prototype.indexOf = function(item){
var l = this.length, i = 0, r = -1;
if(l <= 0){
return -1;
}
for(; i < l; i++){
if(this[i] === item){
r = i;
}
}
return r;
}
}
var result = []; //去重数组
for(var i = 0; i < length; i++){
if(result.indexOf(this[i]) === -1){
result.push(this[i]);
}
}
return result;
}
基于嵌套循环的第六种实现方案
第六种方法的代码示例:
由于Array类型原生未提供去重方法,若需去除数组重复元素,必须自行实现逻辑:
function unique(arr) {
var result = [], isRepeated;
for (var i = 0, len = arr.length; i < len; i++) {
isRepeated = false;
for (var j = 0, len = result.length; j < len; j++) {
if (arr[i] == result[j]) {
isRepeated = true;
break;
}
}
if (!isRepeated) {
result.push(arr[i]);
}
}
return result;
}
总体思路是将数组元素逐个搬运至新数组,并在搬运过程中检查元素是否重复,若重复则丢弃。从嵌套循环的结构可以看出,这种方法效率极低。优化方案是引入hashtable结构记录已有元素,从而避免内层循环,提升性能。
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
