You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

arr.reduce方法返回值疑问:为何错误代码返回数组最后一项而非累加器(数组转键值对象实现场景)

为什么我的arr.reduce实现返回数组最后一项而不是累加器对象?

问题背景

我正在尝试用Array.reduce实现一个groupById函数,把用户数组转换成以id为键的对象。正确的实现能返回预期的键值对象,但我写的错误代码却只返回了数组的最后一项,这让我很困惑。

错误代码如下:

function groupByid(arr){
  return arr.reduce(
    (obj, value) => obj[value.id] = value, {}
  );
}
let users = [
  {id: "john", name: "John Smith", age: 20},
  {id: "ann", name: "Ann Smith", age: 24},
  {id: 'pete', name: "Pete Peterson", age: 31},
];
let userById = groupByid(users);
console.log(userById); // 输出的是最后一个用户对象 {id: 'pete', ...}

而正确的实现是这样的:

function groupByid(arr){
  return arr.reduce(
    (obj, value) => {
      obj[value.id] = value;
      return obj;
    }, {}
  );
}

我想知道为什么错误代码里的reduce没有返回初始传入的累加器对象,反而返回了数组的最后一项?


问题根源:箭头函数的隐式返回规则

这里的核心问题在于箭头函数的隐式返回特性:

  • 当箭头函数的函数体是一个单表达式时,它会自动返回这个表达式的结果,不需要写return关键字。
  • 在你的错误代码中,回调函数是(obj, value) => obj[value.id] = value,这里的表达式是一个赋值操作——obj[value.id] = value。而在JavaScript中,赋值表达式的返回值是被赋予的值(也就是当前的value),而不是赋值操作的目标对象obj。

所以在每一次reduce循环中:

  1. 第一次循环:给obj['john']赋值为第一个用户对象,然后回调返回这个用户对象(而非obj)
  2. 第二次循环:此时累加器不再是初始的空对象,而是上一次返回的第一个用户对象。接着执行累加器['ann'] = 第二个用户对象,然后返回第二个用户对象
  3. 第三次循环:累加器变成第二个用户对象,执行累加器['pete'] = 第三个用户对象,返回第三个用户对象
  4. 循环结束后,reduce返回最后一次回调的返回值,也就是数组的最后一项

如何修复?

你需要确保回调函数每次都返回累加器对象obj,而非赋值操作的结果。有两种常用方式:

  1. 使用花括号包裹函数体,显式写return obj(也就是你给出的正确实现写法)
  2. 如果想保持单表达式的箭头函数,可以用逗号运算符,让表达式最终返回obj:
function groupByid(arr){
  return arr.reduce(
    (obj, value) => (obj[value.id] = value, obj), {}
  );
}

这里逗号运算符会先执行逗号前的赋值操作,然后返回逗号后的obj,这样每次回调都返回累加器对象,就能得到预期的键值对象了。


内容的提问来源于stack exchange,提问作者Malik Yasa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 06:38:13