【问题标题】:Why return a function inside of `array#reduce` instead of just passing a function为什么在`array#reduce`中返回一个函数而不是仅仅传递一个函数
【发布时间】:2017-07-19 09:23:24
【问题描述】:

几周前I asked a question关于如何重新排列数据结构并收到了这个解决方案:

var data = [{ timeline_map: { "2017-05-06": 770, "2017-05-07": 760, "2017-05-08": 1250 } }, { timeline_map: { "2017-05-06": 590, "2017-05-07": 210, "2017-05-08": 300 } }, { timeline_map: { "2017-05-06": 890, "2017-05-07": 2200, "2017-05-08": 1032 } }],
    grouped = data.reduce(function (hash) {
        return function (r, o) {
            Object.keys(o.timeline_map).forEach(function (k) {
                if (!hash[k]) {
                    hash[k] = [k];
                    r.push(hash[k]);
                }
                hash[k].push(o.timeline_map[k]);
            });
            return r;
        };
    }(Object.create(null)), []);

console.log(grouped);

但是再看一遍我不完全确定它是如何工作的 我以前没有见过在 reduce 中返回函数的概念。显然它有效,所以一定有一些原因,但我想澄清一下。

如何在reduce“工作”的这个应用程序中返回一个函数?

【问题讨论】:

    标签: javascript ecmascript-6 reduce


    【解决方案1】:

    基本上它是一个哈希表的闭包,其值为一个真正的空对象。

    grouped = data.reduce(function (hash) {
        return function (r, o) {
            // ...
        };
    }(Object.create(null)), []);
    

    它对变量hash 使用immediately-invoked function expression (IIFE),其范围在回调内部。

    function (hash) {
        return function (r, o) {
            // ...
        };
    }(Object.create(null))
    

    【讨论】:

    • 你能用更多的话解释一下吗?请给一个愚蠢的人?
    • @1252748 它是一个立即调用函数,即立即执行并返回另一个回调。如果您仍有疑问,请查看我的答案。
    • 我只是不明白为什么它需要成为 IIFE。不会立即调用reduce的回调吗?
    • 重点是没有理由这样做。与其解释这些扭曲,不如提供一个不需要它们并且普通人可以理解的解决方案版本。
    • @torazaburo,对,也许不需要它,但我使用自包含方法作为辅助变量,仅用于 reduce 的内部回调。
    【解决方案2】:

    不幸的是,这个答案非常神秘。应该是:

    var data = [{ timeline_map: { "2017-05-06": 770, "2017-05-07": 760, "2017-05-08": 1250 } }, { timeline_map: { "2017-05-06": 590, "2017-05-07": 210, "2017-05-08": 300 } }, { timeline_map: { "2017-05-06": 890, "2017-05-07": 2200, "2017-05-08": 1032 } }];
    
    function group(data) {
      const hash = {};
    
      return data.reduce(function(r, o) {
        Object.keys(o.timeline_map).forEach(function (k) {
          if (!hash[k]) {
            hash[k] = [k];
            r.push(hash[k]);
          }
          hash[k].push(o.timeline_map[k]);
        });
        return r;
      }, []);
    }
    console.log(group(data));
    

    所提供的解决方案涉及一种不明智的尝试,即通过将 hash 对象作为参数的自调用函数来避免分配该对象。

    【讨论】:

    • +1 为前提,但为什么不使用const hash = Object.create(null) 以避免与Object.prototype 的属性发生冲突?
    • 奥术是一个糟糕的词选择。您是否应该使用解决方案取决于解决方案模型的内部一致性和正确解决问题的程度。如果您不了解某事,那么无知是您自己的错,您将因不了解而受到惩罚。与挑战相比,愚蠢更像是一种侮辱。
    • @Arrow 我会坚持使用“奥术”。我是一个非常有经验的 JS 程序员,甚至在查看这段代码时我也做了双重考虑。
    【解决方案3】:

    实际上,您的函数function (hash) { 会在您调用它而不是传递时立即执行,并返回一个回调,该回调将传递给reduce,然后使用该回调调用reduce,很简单。

    编辑

    .reduce(function(hash){...}, []) //meant passing the callback
    .reduce(function(hash){...}**(Object.create(null))**, []) //meant executing the callback
    

    如果

    function someFn(hash) {return 10}
    .reduce(someFn("abc"))
    

    这意味着.reduce 将被10 调用,对吗?因为someFn 将首先调用,它会返回10。同样,如果someFn 返回一个回调呢? reduce 将使用该回调作为参数调用。所以这里的情况与您的情况相同,只是函数someFn 不是更早创建的,而是立即创建和调用的。 (如果你不知道立即调用函数的概念)

    【讨论】:

    • “简单”是相对的。
    • 是的,所以才加了后面的版本来草根讲解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多