V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
teslayun
V2EX  ›  JavaScript

请教一个 reduce 方法的问题

  •  
  •   teslayun · 2021-02-05 16:14:44 +08:00 · 2302 次点击
    这是一个创建于 1420 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    10 条回复    2021-02-05 21:51:21 +08:00
    bearice
        1
    bearice  
       2021-02-05 16:18:21 +08:00   ❤️ 1
    Math.max(undefined,anything) == NaN
    Math.max(NaN,anything) == NaN
    liuy1994g
        2
    liuy1994g  
       2021-02-05 16:19:42 +08:00   ❤️ 1
    isNaN(Math.max(undefined, 2)) === true
    Austaras
        3
    Austaras  
       2021-02-05 16:21:18 +08:00   ❤️ 1
    maxCallback 返回的是数字,数字上没有 ‘x’ 这个属性
    SakuraKuma
        4
    SakuraKuma  
       2021-02-05 16:21:19 +08:00   ❤️ 1
    Math.max 返回的是 Number, 没有.x
    yyfearth
        5
    yyfearth  
       2021-02-05 16:26:56 +08:00   ❤️ 2
    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
        6
    momocraft  
       2021-02-05 16:27:06 +08:00
    从第 2 块的第 3 行向上看
    当 acc 是 22 的时候 ,再和 {x:42} reduce 一次就得到 NaN
    teslayun
        7
    teslayun  
    OP
       2021-02-05 16:27:33 +08:00
    感谢楼上几位大佬解惑,明白了,reduce 里面的函数回调第三次执行的时候 maxCallback 返回的数字没有 X 属性:)
    xngiser
        8
    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
        9
    SoloCompany  
       2021-02-05 19:13:26 +08:00 via iPhone
    类型不匹配,要么先 map 再 reduce,要么 reduce 返回相同套娃结构体
    KuroNekoFan
        10
    KuroNekoFan  
       2021-02-05 21:51:21 +08:00 via iPhone
    reduce 的 api 有点复杂,其实你弄个 forEach 也行的,而且比较好读,就是要多声明一个变量
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5411 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 06:00 · PVG 14:00 · LAX 22:00 · JFK 01:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.