JavaScript数组去重方法详解与代码实现
本文系统总结了JavaScript中实现数组去重的八种常见方法,涵盖对象键值判断、splice删除、indexOf查找、下标对比、排序相邻比较、优化遍历、ES6 Set转换及filter过滤。每种方法均提供基于Array.prototype的完整代码示例,并分析其时间复杂度、空间占用及对原数组的影响,帮助开发者根据实际场景选择最优方案。
基于对象键值与splice删除的基础方法
第一种方法利用对象键值对的特性进行去重。核心思路是创建一个空对象作为哈希表,遍历数组元素,若该元素未作为键存在于对象中,则将其加入结果数组,并将该元素设为对象的键。这种方法在处理简单数据类型时效率较高,但需注意对象键会自动转换为字符串,可能导致数字与字符串混淆。
Array.prototype.unique1 = function () {
var r = {},
temp = []
for (var i = 0; i < this.length; i++) {
if (!r[this[i]]) {
r[this[i]] = 1
temp.push(this[i])
}
}
return temp
}
第二种方法通过splice删除重复元素来实现去重。该算法采用双重循环,外层遍历数组,内层从当前元素的下一位开始查找相同元素。一旦发现重复项,立即使用splice方法将其从原数组中移除,并调整内层循环索引以避免跳过后续元素。此方法直接修改原数组,且由于splice操作涉及数组元素移动,性能相对较低。
Array.prototype.unique2 = function () {
for (var i = 0; i < this.length; i++) {
for (var j = i + 1; j < this.length; j++) {
if (this[i] === this[j]) {
this.splice(j, 1)
j--
}
}
}
return this
}
利用indexOf与下标对比的遍历方案
第三种方法借助数组的indexOf方法。创建一个临时数组,遍历原数组,检查当前元素在临时数组中是否存在(即indexOf返回值是否为-1)。若不存在,则将该元素push到临时数组中。最终返回临时数组。该方法逻辑清晰,但每次indexOf都会遍历临时数组,时间复杂度为O(n^2)。
// 循环遍历当前数组,当前不在临时数组的,push
Array.prototype.unique3 = function () {
var temp = []
for (var i = 0; i < this.length; i++) {
if (temp.indexOf(this[i]) === -1) temp.push(this[i])
}
return temp
}
第四种方法利用数组下标与indexOf返回值的对比。创建一个包含原数组第一个元素的临时数组,从第二个元素开始遍历。如果当前元素在原始数组中第一次出现的位置索引等于当前遍历索引,说明该元素是首次出现,将其加入临时数组。此方法同样依赖indexOf,且未处理原数组顺序改变的问题。
// 当前数组的第i项在当前数组第一次出现的位置不是i,当前项即重复,反之
Array.prototype.unique4 = function () {
var temp = [this[0]]
for (var i = 1; i < this.length; i++) {
if (this.indexOf(this[i]) === i) temp.push(this[i])
}
return temp
}
排序相邻比较与优化遍历策略
第五种方法先对数组进行排序,再比较相邻元素。由于排序会改变原数组的顺序,因此该方法适用于不关心原始顺序的场景。排序后,遍历数组,将当前元素与结果数组的最后一个元素比较,若不同则加入结果数组。需要注意的是,sort()方法默认按字符串Unicode码点排序,数字排序可能不符合预期,需传入比较函数。
// 先排序,找相邻的项
// 这个会改变原来数组的顺序
Array.prototype.unique5 = function () {
var tempArr = this.sort(),
temp = [tempArr[0]]
for (var i = 1; i < tempArr.length; i++) {
if (tempArr[i] !== temp[temp.length - 1]) temp.push(tempArr[i])
}
return temp
}
第六种方法是对遍历算法的优化。通过双重循环,内层查找重复元素时,若发现重复,则跳过当前外层循环的剩余部分,直接处理下一个唯一元素。具体实现中,当发现this[i]与this[j]相等时,通过调整i和j的值来跳过所有重复项,只保留最右侧的一个实例。这种方法避免了多次push操作,但逻辑较为复杂。
// 优化遍历数组
// 获取没重复的最右一值放入新数组
Array.prototype.unique6 = function () {
var temp = []
for (var i = 0; i < this.length; i++) {
for (j = i + 1; j < this.length; j++) {
if (this[i] === this[j]) {
i++;
j = i;
}
}
temp.push(this[i])
}
return temp
}
ES6 Set与filter现代语法实现
第七种方法利用ES6引入的Set数据结构。Set本身只存储唯一值,因此可以直接将数组作为参数创建Set实例,再通过展开运算符[...]将Set转换回数组。这是目前最简洁、高效的去重方式,适用于现代JavaScript环境,且能保持元素原始顺序。
Array.prototype.unique7 = function () {
var temp = new Set(this)
return [...temp]
}
第八种方法使用filter结合indexOf。filter方法遍历数组,对于每个元素,检查其在原数组中第一次出现的索引是否等于当前元素的索引。如果相等,说明该元素是首次出现,保留在结果数组中。这种方法代码简洁,但同样存在O(n^2)的时间复杂度问题,因为indexOf每次都要遍历数组。
Array.prototype.unique8 = function () {
return this.filter(function (ele, index, self) {
return self.indexOf(ele) === index;
})
}
以上总结了八种JavaScript数组去重的实现方式,各有优劣。开发者应根据数据规模、性能要求、是否允许修改原数组以及对ES版本的支持情况,选择最合适的方法。如有疑问或建议,欢迎留言交流。感谢支持!
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58
