map.prototype.keys()返回的迭代器基于创建时刻的快照,不响应后续增删:调用前的修改生效,迭代中新增键不可见,删除键不影响已生成的键序列。

Map.prototype.keys() 返回的迭代器基于创建时刻的 Map 状态快照,它不响应后续的增删操作。识别这种“快照后果”,关键在于理解迭代器何时锁定键序列、哪些修改可见、哪些被忽略。
迭代器启动前的修改全部生效
迭代器只记录调用 map.keys() 那一瞬 Map 中已存在的键(按插入顺序)。
- 调用前插入的键:一定出现在迭代中
- 调用前删除的键:一定不会出现
- 示例:
const map = new Map([['a', 1], ['b', 2]]); map.delete('a'); // 删除在 keys() 前 const iter = map.keys(); console.log([...iter]); // ['b'] —— 不含 'a'
迭代进行中新增键:完全不可见
即使在 for...of 循环中途 map.set('c', 3),新键 'c' 绝不会进入当前迭代器的后续 next() 结果。
- 迭代器不监听 Map 变更,也不重新扫描
- 新增键仅对之后新建的迭代器有效
- 示例:
const map = new Map([['a', 1]]); const iter = map.keys(); map.set('b', 2); // 迭代中插入 console.log(iter.next().value); // 'a' console.log(iter.next().done); // true —— 不会返回 'b'
迭代进行中删除已遍历键:无影响
已通过 next() 取出的键,其对应条目是否被删,不影响迭代器行为;但若尝试用该键 get(),可能返回 undefined。
- 迭代器只管“键列表”,不管键对应值是否存在
- 删除未遍历的键:该键仍会在后续
next()中返回,但map.get(key)可能为undefined - 示例:
const map = new Map([['a', 1], ['b', 2]]); const iter = map.keys(); iter.next(); // { value: 'a', done: false } map.delete('a'); // 已遍历键被删 map.delete('b'); // 未遍历键被删 console.log(iter.next().value); // 'b' —— 键名还在迭代流里 console.log(map.get('b')); // undefined
如何主动检测快照偏差?
没有内置钩子,但可通过以下方式间接判断:
- 对比
map.size和预期键数量(如已知应有 N 个键,但迭代只产出 M 个) - 在迭代前后分别用
[...map.keys()]快照比对,看是否有键“凭空消失”或“意外多出” - 若业务依赖强一致性(如状态同步),避免边遍历边修改;改用
Array.from(map.keys())先固化,再处理
不复杂但容易忽略










