请教一个 reduce 方法的问题

2021-02-05 16:14:44 +08:00
 teslayun

在查阅 MDN 文档的时候看到这个例子:

如果数组为空且没有提供 initialValue,会抛出 TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供 initialValue, 或者有提供 initialValue 但是数组为空,那么此唯一值将被返回并且 callback 不会被执行。

提供初始值通常更安全,正如下面的例子,如果没有提供 initialValue,则可能有四种输出:

var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
var maxCallback2 = ( max, cur ) => Math.max( max, cur );

// reduce() 没有初始值
[ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ); // NaN
[ { x: 2 }, { x: 22 }            ].reduce( maxCallback ); // 22
[ { x: 2 }                       ].reduce( maxCallback ); // { x: 2 }
[                                ].reduce( maxCallback ); // TypeError

// map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行
[ { x: 22 }, { x: 42 } ].map( el => el.x )
                        .reduce( maxCallback2, -Infinity );

这里面第一个数组的 reduce 为啥会返回 NaN 呢,求大佬解惑。 地址: https://developer.mozilla.org/zh-cn/docs/web/javascript/reference/global_objects/array/reduce

2307 次点击
所在节点    JavaScript
10 条回复
bearice
2021-02-05 16:18:21 +08:00
Math.max(undefined,anything) == NaN
Math.max(NaN,anything) == NaN
liuy1994g
2021-02-05 16:19:42 +08:00
isNaN(Math.max(undefined, 2)) === true
Austaras
2021-02-05 16:21:18 +08:00
maxCallback 返回的是数字,数字上没有 ‘x’ 这个属性
SakuraKuma
2021-02-05 16:21:19 +08:00
Math.max 返回的是 Number, 没有.x
yyfearth
2021-02-05 16:26:56 +08:00
reduce 有两个参赛 第一个是一个 function 就和你现在用的一样 但是有第二个参数就是初始值
如果初始值没给 那么第一个元素就是初始值
所以 [ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ) 就是 [ { x: 22 }, { x: 42 } ].reduce( maxCallback, { x: 2 } )
第一次运算 是 { x: 2 } 和 { x: 22 } 结果为 22
第二次运算 是 22 和 { x: 42 } 那么 (22).x 是 undefined 那么 Math.max(undefined, 42) 结果就是 NaN

这就是为什么正确的做法先做了一下 map 把 x 都取出来 然后在 reduce
不过我这样应该是更简单的做法 只不过这个 function 没有普遍性 其他地方可能没办法复用逻辑
[ { x: 22 }, { x: 42 } ].reduce( ( acc, cur ) => Math.max( acc, cur.x ), -Infinity)
momocraft
2021-02-05 16:27:06 +08:00
从第 2 块的第 3 行向上看
当 acc 是 22 的时候 ,再和 {x:42} reduce 一次就得到 NaN
teslayun
2021-02-05 16:27:33 +08:00
感谢楼上几位大佬解惑,明白了,reduce 里面的函数回调第三次执行的时候 maxCallback 返回的数字没有 X 属性:)
xngiser
2021-02-05 16:43:08 +08:00
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );

第一次 acc: { x: 2 } cur: { x: 22 } acc=> 22
第二次 acc: 22 cur: { x: 42 } acc=> NaN
SoloCompany
2021-02-05 19:13:26 +08:00
类型不匹配,要么先 map 再 reduce,要么 reduce 返回相同套娃结构体
KuroNekoFan
2021-02-05 21:51:21 +08:00
reduce 的 api 有点复杂,其实你弄个 forEach 也行的,而且比较好读,就是要多声明一个变量

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/751605

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX