JavaScript数组去重的六种实现方案与性能对比

作者:纸飞机

时间:2026-10-29

浏览:266

本文汇总了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结构记录已有元素,从而避免内层循环,提升性能。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章