用Set管理搜索历史需Set判重+数组控序,先删旧再推新并截取前N项;仅用Set则需delete后add更新位置,再转数组裁剪。

用 Set 管理搜索框历史记录时,关键不是“只去重”,而是“保持最新顺序 + 去重 + 限制数量”。Set 本身不记录插入顺序(ES2015+ 的 Set 实际上是按插入顺序迭代的),但无法直接把某条记录“移到末尾”或“更新位置”。所以需要配合数组或手动维护顺序。
用 Set + 数组协同实现「最新优先、无重复」
推荐做法:用 Set 快速判重,用数组(如 Array)存储并控制顺序和长度。每次新增搜索词时:
- 先从数组中删除已存在的该词(保证它只出现在最后)
- 再推入数组末尾
- 用
Set辅助判断是否存在(O(1) 查找,比array.includes()更高效,尤其在历史较多时) - 截取数组前 N 项(如最多保存 10 条)
示例代码:
class SearchHistory {
constructor(max = 10) {
this.max = max;
this.list = []; // 保持顺序的数组
this.set = new Set(); // 快速查重
}
add(query) {
if (!query || typeof query !== 'string') return;
const trimmed = query.trim();
if (!trimmed) return;
// 如果已存在,先移除旧位置
const index = this.list.indexOf(trimmed);
if (index > -1) {
this.list.splice(index, 1);
this.set.delete(trimmed);
}
// 添加到末尾
this.list.push(trimmed);
this.set.add(trimmed);
// 限制长度
if (this.list.length > this.max) {
const removed = this.list.shift();
this.set.delete(removed);
}
}
getAll() {
return [...this.list]; // 返回副本,避免外部修改
}
clear() {
this.list = [];
this.set.clear();
}
}
// 使用
const history = new SearchHistory(5);
history.add('apple');
history.add('banana');
history.add('apple'); // 会把前面的 apple 移掉,再加到末尾
console.log(history.getAll()); // ['banana', 'apple']
如果坚持只用 Set(不推荐但可行)
仅靠原生 Set 无法直接“把某元素提到最后”,因为 Set 没有索引、不能 splice。但可以利用其「插入顺序保留」特性,通过「删除 + 重新添加」来更新位置:
立即学习“Java免费学习笔记(深入)”;
- 调用
set.delete(item)再set.add(item),就能让它变成最新项 - 转为数组后,用
Array.from(set).slice(-max)取最近的几条 - 注意:每次取历史都要转数组,且无法精确控制“最多 N 条”——因为 Set 不自动裁剪,需手动清理
简易版(适合轻量场景):
const historySet = new Set();
function addToHistory(query) {
if (!query || typeof query !== 'string') return;
const q = query.trim();
if (!q) return;
historySet.delete(q); // 先删(若存在)
historySet.add(q); // 再加 → 成为最新
// 裁剪:转数组,取后 max 条,再重建 Set
const max = 5;
const arr = Array.from(historySet);
if (arr.length > max) {
const recent = arr.slice(-max);
historySet.clear();
recent.forEach(item => historySet.add(item));
}
}
function getRecentHistory() {
return Array.from(historySet); // 最新在后,所以无需 reverse
}
绑定到搜索框的实际建议
结合 DOM 操作时,注意几个实用细节:
- 输入后回车或点击搜索才
add(),避免每打一个字都记录 - 点击历史项时,先
add()再填充到输入框 —— 这样点过的词自动置顶 - 本地持久化可用
localStorage:存JSON.stringify(history.list),读取时校验格式并恢复 Set - 敏感词或空格前后清理(
.trim())、大小写是否区分(如统一转小写)需按产品需求决定
为什么不直接用 Array.includes?
当历史记录达上百条时,array.includes() 是 O(n),而 Set.has() 是 O(1)。虽然对普通用户影响不大,但在高频操作或低性能设备上,用 Set 判重仍是更稳健的选择。真正的瓶颈不在去重,而在「保持顺序 + 更新位置」的逻辑设计。


















