Upsert S4
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2026
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案解决了在更新或插入之前检查 Map 或 WeakMap 中键是否存在的常见问题,这需要多次查找。它引入了 getOrInsert 和 getOrInsertComputed 方法,这些方法返回现有值或在一次调用中插入默认值或计算值。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
Upsert 提案
ECMAScript 提案和参考实现,针对 Map.prototype.getOrInsert、Map.prototype.getOrInsertComputed、
WeakMap.prototype.getOrInsert 和 WeakMap.prototype.getOrInsertComputed。
作者: Daniel Minor (Mozilla) Lauritz Thoresen Angeltveit (Bergen) Jonas Haukenes (Bergen) Sune Lianes (Bergen) Vetle Larsen (Bergen) Mathias Hop Ness (Bergen)
提案负责人: Daniel Minor (Mozilla)
原始作者: Brad Farias (GoDaddy)
前任提案负责人: Erica Pramer (GoDaddy)
阶段: 4
动机
当使用 Map 或 WeakMap 时,一个常见的问题是如何在不确定键是否已经存在于映射中时进行更新。这可以通过首先检查键是否存在,然后根据结果进行插入或更新来处理,但这对开发者来说既不方便,也不是最优的,因为它需要在映射中进行多次查找,而这本来可以通过一次调用完成。
解决方案:getOrInsert
我们提议添加一个方法,如果 key 已经存在于 Map 或 WeakMap 中,则返回与 key 关联的值;否则插入 key 并附带提供的默认值,或调用提供的回调函数的结果,然后返回该值。
此提案的早期版本有一个 getOrInsert 方法,提供两个回调,一个用于 insert,另一个用于 update,但当前的提案负责人认为,按需获取/插入是一个足够常见的用例,因此专注于这一点是有意义的,而不是试图创建一个最大灵活性的 API。它也强烈遵循其他语言中的先例,尤其是 Python。
示例与提议的 API
处理默认值
使用 getOrInsert 简化了默认值的处理,因为它不会覆盖现有的值。
通过使用 getOrInsert,可以在不同的时间应用默认值,并保证后续的默认值不会覆盖现有的值。例如,在有用户偏好、操作系统偏好和应用程序默认值的情况下,我们可以使用 getOrInsert 依次应用用户偏好、操作系统偏好和应用程序默认值,而无需担心覆盖用户的偏好。
增量分组数据
一个典型的用例是根据键将数据分组,随着新值的出现。通过指定默认值而不必在尝试更新之前检查键是否存在于 Map 中,这得到了简化。
诚然,这种模式的常见用例已经被 Map.groupBy 覆盖。然而,该方法要求所有数据在构建分组之前可用;使用 getOrInsert 将允许 Map 增量构建和使用。它还提供了灵活性,可以处理对象以外的数据,例如上面的数组示例。
维护计数器
另一个常见的用例是维护与特定键关联的计数器。使用 getOrInsert 使这更加简洁,并且是一种易于引擎优化的访问然后修改的模式。
计算默认值
对于某些用例,确定默认值可能是一个代价高昂的操作,如果不会使用它,最好避免。在这种情况下,我们可以使用 getOrInsertComputed。
其他语言中的实现
类似的功能在其他语言中也存在。
Java
computeIfPresent重新映射现有条目computeIfAbsent如果为空则插入。使用映射函数计算插入值
Scala
getOrElseUpdate如果缺失则插入。
C++
emplace如果缺失则插入map[] assignment opts如果缺失则插入 在key处,但如果key处存在值,则返回该值insert_or_assign如果缺失则插入。通过替换为特定的新值来更新现有值,而不是通过将函数应用于现有值
C#
GetOrAdd如果键不存在,则添加键/值对并返回新值;如果键已存在,则返回现有值。
Rust
and_modify提供对已占用条目的就地可变访问or_insert_with如果为空则插入。插入值来自映射函数
Python
setdefault执行get和insertdefaultdictdict的子类,带有一个回调函数,用于在get时构造缺失的值。
Elixir
Map.update/4如果键存在,则使用给定函数更新该项,否则插入给定的初始值
规范
Polyfill
该提案可以简单地进行 polyfill: