最高效的js数组去重方法是利用set对象,因其底层基于哈希表,平均时间复杂度为o(n),性能最优;2. filter结合indexof方法兼容性好但时间复杂度为o(n^2),适合小规模数组;3. reduce结合map同样具有o(n)时间复杂度,灵活性高,适用于需要自定义去重逻辑或处理对象数组的场景;4. 对于对象数组去重,需基于唯一标识属性(如id)或组合键使用filter加set/map,或利用map覆盖机制保留最后出现的元素;5. set、filter+indexof和reduce+map三种方法在现代javascript环境中均能保持元素的原始顺序,其中set在实际引擎实现中按插入顺序迭代,确保去重后顺序一致;综上,优先推荐使用set进行基本类型去重,在需要兼容性或复杂逻辑时选用reduce加map方案,对象数组则依据属性定义唯一性标准进行处理,所有方法均能有效保持原始顺序。

JS数组去重,说白了,就是把一个数组里重复的元素给剔除掉,只留下那些独一无二的。这事儿在前端开发里挺常见的,比如你从后端拿到一份数据列表,里面可能因为各种原因出现了重复项,这时候你就得想办法把它“洗干净”。选择哪种方法,其实挺看你的具体场景和对性能、代码简洁度的偏好。
利用Set对象去重是最现代也最直接的方式。Set是ES6引入的一种新的数据结构,它最大的特点就是成员的值都是唯一的。所以,把数组扔进Set里走一圈,再把它变回数组,基本上就搞定了。
const originalArray = [1, 2, 2, 'hello', 'world', 'hello', null, null, undefined, undefined, NaN, NaN, {}, {}];
const uniqueArrayBySet = [...new Set(originalArray)];
console.log(uniqueArrayBySet);
// 结果:[1, 2, 'hello', 'world', null, undefined, NaN, {}, {}]
// 注意:Set在处理NaN时,会认为所有NaN都是同一个值,但对于对象,它会认为两个空对象字面量({})是不同的,因为它们的引用地址不同。这种方法代码量极少,可读性也好,对于基本数据类型(数字、字符串、布尔值、null、undefined、NaN)去重非常高效和准确。但记住一点,它对对象的去重是基于引用地址的,两个内容完全一样的对象,如果内存地址不同,Set会把它们当作两个不同的元素。
除了Set,我们也可以利用数组自身的
filter()
indexOf()
const originalArray = [1, 2, 2, 'hello', 'world', 'hello', null, null, undefined, undefined, NaN, NaN];
const uniqueArrayByFilter = originalArray.filter((item, index, self) => {
// indexOf会返回元素在数组中第一次出现的索引
// 如果当前元素的索引和它第一次出现的索引相同,说明它是第一次出现,就保留
return self.indexOf(item) === index;
});
console.log(uniqueArrayByFilter);
// 结果:[1, 2, 'hello', 'world', null, undefined, NaN]
// 注意:indexOf在处理NaN时,会有些“奇怪”,因为NaN !== NaN,所以indexOf(NaN)总是-1,可能导致多个NaN被保留。
// 同样,它也无法直接处理对象去重。这种方式的优点是兼容性好,在老旧浏览器环境里也能跑。但它的性能在数组元素较多时会明显下降,因为
indexOf
再者,如果我们需要更精细的控制,或者要兼顾性能和顺序,
reduce()
Map
const originalArray = [1, 2, 2, 'hello', 'world', 'hello', null, null, undefined, undefined, NaN, NaN];
const seenMap = new Map(); // 或者用一个普通对象 {}
const uniqueArrayByReduce = originalArray.reduce((accumulator, currentItem) => {
// Map的key可以是任何类型,包括NaN,并且对NaN的判断是正确的
if (!seenMap.has(currentItem)) {
seenMap.set(currentItem, true);
accumulator.push(currentItem);
}
return accumulator;
}, []);
console.log(uniqueArrayByReduce);
// 结果:[1, 2, 'hello', 'world', null, undefined, NaN]
// 这个方法能正确处理NaN,并且保持了元素的原始顺序。这种方法在性能上通常比
filter
indexOf
谈到效率,这事儿就得具体分析了。在我看来,大多数时候,
Set
相比之下,
filter()
indexOf()
indexOf()
filter
至于
reduce()
Map
Set
所以,如果问我哪种最快,我通常会毫不犹豫地指向
Set
reduce
Map
处理对象数组去重,这可就不是简单地用Set或者
indexOf
{id: 1, name: 'A'}{id: 1, name: 'A'}这时候,我们就需要定义一个“唯一性”的标准。通常,我们会基于对象的一个或多个属性来判断它们是否重复。比如,如果你的对象都有一个
id
id
id
一个比较常见的做法是结合
filter()
Set
Map
id
const users = [
{ id: 1, name: 'Alice', age: 30 },
{ id: 2, name: 'Bob', age: 25 },
{ id: 1, name: 'Alice', age: 30 }, // 重复项
{ id: 3, name: 'Charlie', age: 35 },
{ id: 2, name: 'Bob', age: 26 } // id重复,但age不同
];
const seenIds = new Set();
const uniqueUsers = users.filter(user => {
// 如果这个id之前没见过
if (!seenIds.has(user.id)) {
seenIds.add(user.id); // 把它标记为已见过
return true; // 保留这个用户对象
}
return false; // 否则,丢弃
});
console.log(uniqueUsers);
// 结果:
// [
// { id: 1, name: 'Alice', age: 30 },
// { id: 2, name: 'Bob', age: 25 },
// { id: 3, name: 'Charlie', age: 35 }
// ]这种方式非常实用,因为它允许你自定义去重的逻辑。如果对象的唯一性需要由多个属性共同决定,比如
id
type
user.id + '-' + user.type
另一种稍微复杂但更通用的方法是利用
Map
const users = [
{ id: 1, name: 'Alice', age: 30 },
{ id: 2, name: 'Bob', age: 25 },
{ id: 1, name: 'Alice', age: 30 },
{ id: 3, name: 'Charlie', age: 35 },
{ id: 2, name: 'Bob', age: 26 } // id重复,但age不同,我们希望保留最新的(即这个)
];
const uniqueMap = new Map();
users.forEach(user => {
// 以id作为key,每次遇到重复id,新的对象会覆盖旧的,从而保留最后一个
uniqueMap.set(user.id, user);
});
const uniqueUsersFromMap = Array.from(uniqueMap.values());
// 或者 [...uniqueMap.values()]
console.log(uniqueUsersFromMap);
// 结果:
// [
// { id: 1, name: 'Alice', age: 30 },
// { id: 2, name: 'Bob', age: 26 }, // 注意,这里保留了age为26的Bob
// { id: 3, name: 'Charlie', age: 35 }
// ]这种
Map
JSON.stringify()
去重的时候,很多时候我们不仅要剔除重复项,还希望剩下的元素能保持它们在原始数组中的相对顺序。这其实是个挺重要的细节,因为数据的顺序有时会承载特定的业务含义。
幸运的是,我们前面提到的一些主流去重方法,在现代JavaScript环境中,大多都能很好地保持原始顺序。
Set
Set
Set
[...new Set(arr)]
filter()
indexOf()
reduce()
Map
reduce
push
// 示例:使用reduce + Map 保持顺序
const disorderedArr = ['apple', 'banana', 'apple', 'orange', 'banana', 'grape'];
const uniqueAndOrdered = disorderedArr.reduce((acc, item) => {
if (!seenMap.has(item)) { // 假设seenMap已定义
seenMap.set(item, true);
acc.push(item);
}
return acc;
}, []);
console.log(uniqueAndOrdered); // ['apple', 'banana', 'orange', 'grape'] - 顺序完全保留所以,你不需要为了保持顺序而额外做太多工作。选择Set或者
reduce
Map
filter
indexOf
以上就是js如何实现数组去重的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号