技术解析

请教一个 reduce 方法的问题
0
2021-08-11 03:39:57
idczone

在查阅 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


Math.max(undefined,anything) == NaN
Math.max(NaN,anything) == NaN

isNaN(Math.max(undefined, 2)) === true

maxCallback 返回的是数字,数字上没有 ‘x’ 这个属性

Math.max 返回的是 Number, 没有.x

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)

从第 2 块的第 3 行向上看
当 acc 是 22 的时候 ,再和 {x:42} reduce 一次就得到 NaN

感谢楼上几位大佬解惑,明白了,reduce 里面的函数回调第三次执行的时候 maxCallback 返回的数字没有 X 属性:)

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

类型不匹配,要么先 map 再 reduce,要么 reduce 返回相同套娃结构体

reduce 的 api 有点复杂,其实你弄个 forEach 也行的,而且比较好读,就是要多声明一个变量

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服