保尾去重核心是保留元素最后一次出现的位置:1. filter+lastindexof简洁但仅适用于基本类型;2. 对象记录最后索引有类型限制;3. map支持全类型但顺序非严格尾序;4. 反向遍历+set最准确高效。

用 filter + lastIndexOf 保尾去重
核心思路是:只保留当前元素在数组中最后一次出现的位置等于它当前索引的那些项。这样,每个值最终只留下它「最靠后」的一次出现。
代码写法简洁直接:
const uniqueByLast = arr => arr.filter((item, index) => arr.lastIndexOf(item) === index);
例如:
const arr = [1, '1', 2, 1, '1', 3];
console.log(uniqueByLast(arr)); // → ['1', 2, 1, 3]
注意:数字 1 和字符串 '1' 被视为不同元素,各自独立判断最后位置;结果中 1 出现在 '1' 之后,是因为它在原数组里更靠右。
手动遍历 + 对象记录最后索引
如果需要更高可控性(比如兼容老环境、或想提前终止),可以用 for 循环配合对象缓存每个值的最后出现位置:
const uniqueByLast = arr => {
const lastIndex = {};
for (let i = 0; i
lastIndex[arr[i]] = i;
}
return Object.keys(lastIndex).map(key => arr[lastIndex[key]]);
};
⚠️ 注意:这种方法会把所有键转成字符串,所以 1 和 '1' 会冲突,null、undefined、对象 等也会出错。如需支持全类型,得改用 Map 存储原始值。
用 Map 实现全类型安全的尾去重
当数组含对象、NaN、Symbol 或混合类型时,Object 键不可靠,推荐用 Map:
const uniqueByLast = arr => {
const map = new Map();
for (let i = 0; i
map.set(arr[i], i);
}
return Array.from(map.values()).map(i => arr[i]);
};
✅ 它能正确处理:
– NaN === NaN(Map 中 NaN 可作键)
– 对象引用(不同对象不会误判为重复)
– Symbol、布尔值、undefined 等所有原始类型
❌ 缺点:不保持原始顺序中的「相对尾序」——因为 Map 的 key 遍历顺序是插入顺序,而我们是按索引存再按 key 遍历,所以最终顺序取决于各值**首次被设进 Map 的时机**,不是严格按最后位置从左到右排。若强依赖该顺序,仍建议用 first 方法反向遍历。
反向遍历 + includes 实现真正保尾且保序
想让结果数组中元素顺序和它们「最后一次出现的位置」升序一致(即越靠后的重复值越靠前),可从后往前遍历,再反转:
const uniqueByLast = arr => {
const seen = new Set();
const res = [];
for (let i = arr.length - 1; i >= 0; i--) {
if (!seen.has(arr[i])) {
seen.add(arr[i]);
res.push(arr[i]);
}
}
return res.reverse();
};
这个版本逻辑清晰、性能好(O(n))、类型安全、顺序准确,适合多数生产场景。











