目录

🗑 JavaScript 弱映射与弱集合应用实例

# WeakSet

# 信息已读

有一个 messages 数组:

let messages = [
  {text: "Hello", from: "John"},
  {text: "How goes?", from: "John"},
  {text: "See you soon", from: "Alice"}
];
1
2
3
4
5

可以访问它,但是 message 是由其他人的代码管理的。该代码会定期添加新消息,删除旧消息,但是你不知道这些操作确切的发生时间。

应该使用什么数据结构来保存关于消息「是否已读」的信息?该结构必须很适合对给定的 message 对象给出「它读了吗?」的答案。

  • 当一个消息被从 messages 中删除后,它应该也从你的数据结构中消失。
  • 不能修改 message 对象,例如向其添加属性。因为它们是由其他人的代码管理的,修改该数据可能会导致不好的后果。
点击查看
let readMessages = new WeakSet()

readMessages.add(message[0]) // 读信息
readMessages.add(message[1]) // 读信息

// 再次读信息
readMessages.add(message[0]) // 不再添加已读

// 检查是否已读
readMessages.has(message[0]) // true 意味着信息已读

messages.shift(); // 信息被清理
// readMessages 会跟随清理
1
2
3
4
5
6
7
8
9
10
11
12
13

使用 WeakSet 的代价:不能对它进行迭代,也不能直接从中获取「所有已读消息」。但是,可以通过遍历所有消息,然后找出存在于 set 的那些消息来完成这个功能。

另一个解决方法:在读取消息后向消息添加诸如 message.isRead=true 之类的属性。由于 messages 对象是由另一个代码管理的,因此通常不建议这样做,但是可以使用 symbol 属性来避免冲突。

let isRead = Symbol("isRead");
messages[0][isRead] = true;
1
2

现在,第三方代码可能看不到这个额外属性。尽管 symbol 可以降低出现问题的可能性,但从架构的角度来看,还是使用 WeakSet 更好。

# 保存阅读日期

与上题类似,但是保存阅读记录以外,还需要保存日期。并且它应该在消息被垃圾回收时也被从内存中清除。

点击查看
let messages = [
  {text: "Hello", from: "John"},
  {text: "How goes?", from: "John"},
  {text: "See you soon", from: "Alice"}
];

let readMap = new WeakMap();

readMap.set(messages[0], new Date());
1
2
3
4
5
6
7
8
9
📢 上次更新: 2022/09/02, 10:18:16