javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS数据去重方法

JS数据去重的7种实用方法总结(附完整代码与原理)

作者:前端开发小透明

在JavaScript中数据去重是一个常见的操作,特别是在处理数组时,这篇文章主要介绍了JS数据去重的7种实用方法,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在 JavaScript 开发中,“数据去重” 是高频需求 —— 比如处理接口返回的重复列表、用户输入的重复值等。不同场景下,适合的去重方法不同,有的追求简洁,有的追求性能,有的需要兼容复杂数据类型。今天就整理 7 种常用的去重方法,每种都附带代码和核心原理,帮你轻松应对各种去重场景。

一、基础方法:利用 Set 去重(最简洁)

核心原理:ES6 新增的 Set 集合本身具有 “值唯一” 的特性,能自动忽略重复值,再通过扩展运算符(...)或 Array.from() 转回数组即可。

代码实现

// 待去重数组(包含数字、字符串、重复值)
const arr = [1, 2, 2, "3", "3", 4, 4, 5];
// 方法 1:扩展运算符转数组
const uniqueArr1 = [...new Set(arr)];
// 方法 2:Array.from() 转数组(兼容不支持扩展运算符的环境)
const uniqueArr2 = Array.from(new Set(arr));
console.log(uniqueArr1); // 输出:[1, 2, "3", 4, 5]
console.log(uniqueArr2); // 输出:[1, 2, "3", 4, 5]

优缺点

适用场景

处理简单数据类型(数字、字符串、布尔值)的数组,追求代码简洁和性能。

二、传统方法:利用 indexOf/includes 去重

核心原理:创建一个新数组,遍历原数组,判断当前元素是否在新数组中(用 indexOfincludes),不在则加入新数组,最终得到去重后的数组。

代码实现(indexOf 版)

const arr = [1, 2, 2, 3, 3, 3];
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
 // indexOf 返回 -1 表示元素不在新数组中
 if (uniqueArr.indexOf(arr[i]) === -1) {
   uniqueArr.push(arr[i]);
 }
}
console.log(uniqueArr); // 输出:[1, 2, 3]

代码实现(includes 版,更直观)

const arr = [1, 2, 2, 3, 3, 3];
const uniqueArr = [];
for (let item of arr) {
 // includes 直接返回布尔值,判断元素是否存在
 if (!uniqueArr.includes(item)) {
   uniqueArr.push(item);
 }
}
console.log(uniqueArr); // 输出:[1, 2, 3]

优缺点

适用场景

处理小规模的简单类型数组,或需要兼容低版本浏览器的场景。

三、优化性能:利用对象键名唯一性去重

核心原理:对象的键名(key)具有唯一性(不能重复),遍历原数组时,把元素作为对象的键名存储,同时判断键名是否已存在,不存在则加入新数组。

代码实现

const arr = [1, 2, 2, "2", 3, 3];
const uniqueArr = [];
const tempObj = {}; // 临时对象,用于存储已存在的元素
for (let item of arr) {
 // 把元素转为字符串作为键名(避免 1 和 "1" 被视为不同键)
 const key = typeof item + item;
 if (!tempObj[key]) {
   tempObj[key] = true; // 标记为已存在
   uniqueArr.push(item);
 }
}
console.log(uniqueArr); // 输出:[1, 2, "2", 3]

关键细节

优缺点

适用场景

处理大规模的简单类型数组,追求高性能,且需要区分值类型。

四、进阶方法:利用 filter + indexOf 去重

核心原理filter 方法会筛选出满足条件的元素,结合 indexOf 判断 “当前元素在原数组中的第一次出现位置是否等于当前索引”—— 如果等于,说明是第一次出现,保留;否则是重复值,过滤掉。

代码实现

const arr = [1, 2, 2, 3, 3, 4];
// filter 回调函数:返回 true 则保留元素
const uniqueArr = arr.filter((item, index) => {
 // indexOf 会返回元素在数组中第一次出现的索引
 return arr.indexOf(item) === index;
});
console.log(uniqueArr); // 输出:[1, 2, 3, 4]

优缺点

适用场景

处理小规模简单类型数组,追求函数式编程风格,不关心极致性能。

五、ES6 进阶:利用 Map 去重

核心原理Map 的键(key)可以是任意类型,且具有唯一性。遍历原数组时,用 Map.has() 判断元素是否已存在,不存在则用 Map.set() 存储,并加入新数组。

代码实现

const arr = [1, 2, 2, "3", "3", 4];
const uniqueArr = [];
const tempMap = new Map();
for (let item of arr) {
 if (!tempMap.has(item)) { // 判断元素是否已在 Map 中
   tempMap.set(item, true); // 存储元素(值随便设,只要有标记即可)
   uniqueArr.push(item);
 }
}
console.log(uniqueArr); // 输出:[1, 2, "3", 4]

优缺点

适用场景

处理简单类型数组,或需要存储 NaN 等特殊值的场景(indexOf 无法判断 NaN,但 Map.has(NaN) 可以)。

六、复杂场景:引用类型(对象 / 数组)去重

前面的方法都无法处理对象 / 数组等引用类型(比如 { id: 1 }{ id: 1 } 会被视为不同值,因为引用不同)。此时需要通过 “比较内容” 来实现去重,常用方法是 JSON.stringify 转字符串手动比较属性

方法 1:JSON.stringify 转字符串(简单对象适用)

核心原理:把对象转为 JSON 字符串,再用 Set 或对象键名去重(字符串可以被唯一识别)。

// 待去重的对象数组(id 相同视为重复)
const arr = [
 { id: 1, name: "小明" },
 { id: 1, name: "小明" }, // 重复
 { id: 2, name: "小红" }
];
const uniqueArr = [...new Set(arr.map(item => JSON.stringify(item)))]
 .map(str => JSON.parse(str)); // 转回对象
console.log(uniqueArr);
// 输出:[{ id: 1, name: "小明" }, { id: 2, name: "小红" }]

方法 2:手动比较属性(复杂对象适用)

核心原理:指定一个唯一标识(比如 id),遍历数组时,判断新数组中是否已有该标识的对象,没有则加入。

const arr = [
 { id: 1, name: "小明" },
 { id: 1, name: "小明" },
 { id: 2, name: "小红" }
];
const uniqueArr = [];
for (let item of arr) {
 // 用 some 判断新数组中是否已有相同 id 的对象
 const isRepeat = uniqueArr.some(uniqueItem => uniqueItem.id === item.id);
 if (!isRepeat) {
   uniqueArr.push(item);
 }
}
console.log(uniqueArr);
// 输出:[{ id: 1, name: "小明" }, { id: 2, name: "小红" }]

优缺点

适用场景

处理对象数组,且对象结构简单(无特殊属性),或有明确唯一标识(如 id)的场景。

七、排序后去重:利用 sort + 相邻比较

核心原理:先通过 sort() 把数组排序(相同元素会相邻),再遍历排序后的数组,比较当前元素和前一个元素,不同则加入新数组。

代码实现

const arr = [3, 1, 2, 2, 3, 1, 4];
const uniqueArr = [];
// 先排序(注意:sort 默认按字符串排序,数字需加比较函数)
const sortedArr = arr.sort((a, b) => a - b); // 排序后:[1, 1, 2, 2, 3, 3, 4]
for (let i = 0; i < sortedArr.length; i++) {
 // 比较当前元素和前一个元素,不同则保留
 if (sortedArr[i] !== sortedArr[i - 1]) {
   uniqueArr.push(sortedArr[i]);
 }
}
console.log(uniqueArr); // 输出:[1, 2, 3, 4]

优缺点

适用场景

处理数字数组,且不关心原数组顺序的场景。

总结:不同场景如何选?

场景需求推荐方法时间复杂度
简单类型 + 代码简洁Set 去重O(n)
简单类型 + 高性能 + 大规模对象键名去重 / Map 去重O(n)
低版本浏览器兼容indexOf/includes 去重O(n²)
函数式编程风格filter + indexOf 去重O(n²)
对象数组(有唯一标识)手动比较属性去重O(n²)
数字数组(不关心顺序)sort + 相邻比较去重O(n log n)

记住:没有 “最好” 的去重方法,只有 “最适合” 的 —— 根据数据类型、数据规模和环境需求选择即可!

到此这篇关于JS数据去重的7种实用方法总结的文章就介绍到这了,更多相关JS数据去重方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文