写过 JS 的人都踩过这个坑——reduce 算金额永远差一分、Map 要写三行 if-else,Error 判断跨 realm 直接失效。今天 ES2026 用三个 API 把这些彻底修了

写过 JS 的人都踩过这个坑——reduce 算金额永远差那么一分、Map 取个默认值要写三行 if-else、判断一个值是不是真正的 Error 跨 realm 直接失效。这些问题不是一个,是三个,但今天 ES2026 用三个 API 把它们一起修了。

1. Math.sumPrecise:浮点求和终于不用自己造轮子

先说最典型的那个。JavaScript 浮点精度丢数据这事儿,写过金融计算的都懂:

// 这样写,在大数面前直接翻车
const total = [0.1, 0.2, 0.3].reduce((a, b) => a + b, 0);
// 浏览器里跑,结果是 0.6000000000000001

更隐蔽的是这种:

const nums = [1e20, 0.1, -1e20];
nums.reduce((a, b) => a + b, 0); // 0,0.1 被大数直接吞了

ES2026 的 Math.sumPrecise 用的是 Shewchuk 精确求和算法,先用高精度把结果算完,最后才转回 float64:

const total = Math.sumPrecise([0.1, 0.2, 0.3]);
// 0.6,精确的

const nums = [1e20, 0.1, -1e20];
Math.sumPrecise(nums); // 0.1,0.1 没被吞掉

参数是 iterable,所以 Math.sumPrecise([1, 2, 3]) 可以,Math.sumPrecise(values) 也可以,但不支持 Math.sumPrecise(1, 2, 3) 展开传参。

Chrome 147+ / Firefox 137+ / Safari 26.2+ / Node.js 22+ 已支持。财务系统、LLM token 预算统计、科学计算场景,直接换掉 reduce((a, b) => a + b, 0) 就行。

2. Map.getOrInsert / getOrInsertComputed:缓存模式从三行到一行

这个痛点几乎每个写 Map 的人都遇到过。缓存一个值,标准写法是:

if (!cache.has(key)) {
  cache.set(key, defaultValue);
}
return cache.get(key);

三行,两个操作(has + get),而且中间还有一次重复的 key 查找。getOrInsert 把这个变成一行:

const value = cache.getOrInsert(key, defaultValue);
// key 存在 → 返回已有值
// key 不存在 → 插入 defaultValue 并返回

对于那些初始化成本高的默认值,getOrInsertComputed 登场了——回调函数只在 key 真正缺失时才执行:

const user = cache.getOrInsertComputed(userId, (id) => {
  console.log('creating cache for:', id);
  return loadUserFromDB(id);
});
// 第一次调用:打印日志 + 查库 + 缓存
// 之后调用:直接返回缓存值,回调不跑

这个方法 WeakMap 上也有,行为一致。

3. Error.isError:跨 realm 判断 Error 终于靠谱了

这个问题在做微前端、module federation 或者 worker 通信的人应该遇过:

const frame = document.createElement('iframe');
// iframe 里的 Error
const err = frame.contentWindow.Error;
// 这个 instanceof 永远是 false
err instanceof Error; // false ❌

传统手段 instanceof 查的是原型链,realm 边界一过就失效。你可能还试过这个:

err.constructor.name === 'Error'; // 可惜可以伪造

Error.isError 用的是内部槽位检查,不依赖原型链,跨 realm 也准:

Error.isError(new Error('boom'));           // true
Error.isError(new TypeError('bad'));        // true
Error.isError({ message: 'fake error' });   // false
Error.isError('just a string');             // false

写错误处理中间件、做错误归因、做告警系统的人,这个 API 救了命。

下一步

三个 API 都不需要 polyfill,Chrome 147+ / Firefox 137+ / Safari 26.2+ / Node.js 22+ 直接用。生产项目现在就可以逐步替换:

  • 金额计算:把 reduce((a, b) => a + b, 0) 换成 Math.sumPrecise
  • Map 缓存:搜索 has + get + set 三连模式,改成 getOrInsertgetOrInsertComputed
  • 错误处理:把 instanceof Error 检查换成 Error.isError

这三个都不大,但每个都省掉一整类本来需要手写 workaround 的场景。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 16 阅读