Set比数组更适合做订阅者列表,因其自动去重、add/delete/has操作时间复杂度均为O(1),而数组需手动判断且查找为O(n);SubscriberList类用Set封装订阅管理,并通过标准化输入和复合键支持多标识订阅。
用 JavaScript 的 Set 实现订阅者列表,天然避免重复——因为 Set 只存储唯一值,插入相同值不会生效,也不报错。
Set 内部基于键值对(键和值相同)实现去重,插入重复邮箱、ID 或用户名时自动忽略;而用数组需手动 includes() 或 findIndex() 判断,逻辑冗余且易出错。另外,Set 的 add()、delete()、has() 时间复杂度都是 O(1),比数组的 O(n) 查找更高效。
定义一个 SubscriberList 类封装行为,内部用 Set 存储订阅者标识(如用户邮箱):
class SubscriberList { constructor() { this.subscribers = new Set(); } // 订阅(自动去重) subscribe(email) { if (typeof email !== 'string' || !email.trim()) return false; this.subscribers.add(email.trim().toLowerCase()); return true; } // 取消订阅 unsubscribe(email) { return this.subscribers.delete(email.trim().toLowerCase()); } // 检查是否已订阅 isSubscribed(email) { return this.subscribers.has(email.trim().toLowerCase()); } // 获取当前订阅人数 count() { return this.subscribers.size; } // 获取所有订阅者(可选转为数组) all() { return Array.from(this.subscribers); }}
"[email protected]" 和 "[email protected] " 被视为不同用户subscribers[0] 访问——Set 不支持下标访问,要用 Array.from(set)[0] 或迭代器for...of 或 forEach,例如:this.subscribers.forEach(email => sendEmail(email))
Set 是内存数据,刷新页面即丢失;如需持久,订阅后应同步存到 localStorage 或后端如果业务中用户可能用邮箱、手机号或 UID 订阅,可稍作改造,让 subscribe(id, type = 'email') 支持复合键:
// 示例:用类型+值拼接成唯一键subscribe(id, type = 'email') { const key = `${type}:${String(id).trim().toLowerCase()}`; this.subscribers.add(key);}
这样既能保持去重逻辑简洁,又保留了多维度识别能力。