简单的JavaScript Reduce函数

3

我正在处理一个非常简单的数据集,使用 reduce 函数进行操作,但是得到了 NaN 的结果,这不是我期望的:

let students = [{name: 'Leah', grade: 94},{name: 'Savannah', grade: 73},{name: 'Killian', grade: 38}];

let highest = students.reduce(
    (high, current) => Math.max(high.grade, current.grade)
    )

console.log(highest); // outputs NaN

奇怪的是,如果我将第一行改为以下内容:(只删除第三个对象)
let students = [{name: 'Leah', grade: 94},{name: 'Savannah', grade: 73}];

如果只有前面的内容,程序将正确运行并输出94。


为什么添加一个额外的对象会导致问题?


4
使用调试器逐步执行你的代码。每次循环时,检查highcurrent的值。你应该能够很快找出问题所在。 - user663031
2个回答

6
这一切都与累加器(high)中的内容有关。如果您没有为reduce提供第二个参数,则累加器将以第一个对象作为起始值,当前元素是第二个元素。在第一次迭代中,您将累加器视为对象,并使用high.grade获取成绩; 但然后您返回一个数字(94),而不是一个对象,以成为下一个累加器。在循环的下一次迭代中,high不再是一个对象,而是94,因此,(94).grade就没有意义了。

当您删除第三个元素时,就没有第二次迭代的机会了,也就没有错误发生的时间,您会得到当前累加器的值(94)。如果只有一个元素,您将得到初始累加器({ name:'Leah',grade:94 })。显然,这并不理想,因为无法可靠地预测计算结果的形状(对象、数字或错误)。

您需要决定是要数字还是对象,二者之一。

let highest = students.reduce(
    (high, current) => Math.max(high, current.grade),
    Number.NEGATIVE_INFINITY
)

这种变体将累加器保留为数字,并返回94。我们不能依赖默认的起始累加器,因为它需要是一个数字,所以我们人为地将其设置为-INF

let highest = students.reduce(
    (high, current) => high.grade > current.grade ? high : current,
)

这是对象版本,其中highest最终变成{name: 'Leah', grade: 94}

谢谢,我应该看到那个的。如果再添加一个对象,那么我在这个 mozilla 页面 上的例子会失败,我的说法正确吗?(就在说明标题下的第一个示例) - qarthandso
是的,如果您添加另一个对象,它将返回NaN。您可以在控制台中轻松测试以进行验证。 - user5004821
@qarthandso 在描述下方的第一个示例中,他们说你应该使用.map和初始值而不是没有初始值的reduce()示例。但他们也应该包括三个对象的失败情况。 - t.niese
1
实际上,我相信这个例子的存在恰恰是为了警告这种情况(即没有初始值时,你需要非常小心,因为有几种不同的情况可能会发生)。该示例与您的情况完全相似。当您未指定初始值时,回调返回值的类型需要与第一个元素的类型匹配,否则将导致混乱。 - Amadan

2
这里的问题在于第一次传递后累加器(high)是一个数字(由math.max返回),但每次传递都要求high为带有成绩作为数字属性的对象。因此,在第二次调用时,您调用了Math.max(undefined, 73) - 这将返回NaN。相反,我建议使用-Infinity初始化累加器,并仅提供highlet highest = students.reduce( (high, current) => Math.max(high, current.grade) , -Infinity)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接