for of手动去重是遍历原数组,将未出现的元素逐个推入新数组;支持自定义判断(如Object.is处理NaN)、按属性去重,逻辑清晰兼容性好,但includes方式时间复杂度为O(n²)。

用 for of 循环手动去重,核心是遍历原数组,把**没出现过的元素**逐个推入新数组。它不依赖 Set 或 filter 等高级方法,逻辑清晰、兼容性好,适合理解去重本质或需自定义判断规则的场景。
基础写法:用 includes 判断是否已存在
这是最直观的方式:新建一个空数组,遍历原数组每一项,若新数组里还不包含该项,就 push 进去。
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = [];
for (const item of arr) {
if (!unique.includes(item)) {
unique.push(item);
}
}
console.log(unique); // [1, 2, 3, 4, 5]
- 优点:代码易读,支持字符串、数字等基本类型
-
注意:includes 对 NaN 返回 false(但 NaN === NaN 是 false),所以
[NaN, NaN]会被去成[NaN, NaN];对象引用比较也不适用
处理对象数组:按某个属性去重
如果数组里是对象,通常希望按 id、name 等字段去重。这时不能直接用 includes,得手动检查属性值是否已存在。
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice2' }, // id 重复
{ id: 3, name: 'Charlie' }
];
const uniqueUsers = [];
const seenIds = new Set(); // 辅助记录已见 id
for (const user of users) {
if (!seenIds.has(user.id)) {
seenIds.add(user.id);
uniqueUsers.push(user);
}
}
console.log(uniqueUsers);
// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
- 用 Set 存已出现的 key 比每次遍历数组查更快(O(1) 查找)
- 也可用普通对象
{}当哈希表,如if (!seen[user.id]) { seen[user.id] = true; ... }
兼容 NaN 和简单对象的增强判断
若需正确处理 NaN(ES6 中 NaN !== NaN),可用 Array.prototype.findIndex 配合 Object.is —— 它能正确识别 NaN 相等:
立即学习“Java免费学习笔记(深入)”;
const arr = [1, NaN, 2, NaN, 3];
const unique = [];
for (const item of arr) {
const exists = unique.findIndex(x => Object.is(x, item)) !== -1;
if (!exists) {
unique.push(item);
}
}
console.log(unique); // [1, NaN, 2, 3]
-
Object.is(a, b)比===更严格,能区分+0和-0,且Object.is(NaN, NaN) === true - 此方式也适用于需要深比较的极简场景(但复杂对象仍建议用专门库)
性能小提醒
纯 for of + includes 的时间复杂度是 O(n²),大数据量时略慢。如只需快速去重且不要求兼容老环境,优先用 [...new Set(arr)];但若要手动控制逻辑(比如保留最后出现的项、或合并对象字段),for of 就非常灵活。


















