使用reduce方法进行管道操作

3

2016年10月,trincot在stackoverflow上发表了一篇关于使用reduce方法构建管道函数的优秀文章(链接),我正在尝试详细理解其中的代码。

ES6版本

function piper(...fs) {
    return (...args) => fs.reduce((args,f) => [f.apply(this,args)],args)[0];
}

具体来说:
1. 与其使用 [f.apply(this.args)]f(...args) 也可以工作,但 f(args) 不起作用。为什么 f(args) 不起作用?
2. 关于内部(匿名)“reduce”函数中的第二个参数,为什么需要 args?即为什么以下代码不起作用?

function piper(...fs) {
    return (...args) => fs.reduce((args,f) => [f.apply(this,args)])[0];
}

B. 或者,为什么我们不能只使用[]作为参数,而不是args
function piper(...fs) {
    return (...args) => fs.reduce((args,f) => [f.apply(this,args)],[])[0];
}

ES5版本

function piper(/* functions */) {
    var fs = [].slice.apply(arguments);    
    return function (/* arguments */) { 
        return fs.reduce(function (args,f) {
            return [f.apply(this,args)];
        }.bind(this), [].slice.apply(arguments))[0];
    }.bind(this);
}

问题: 1. 在内部(匿名)reduce函数中,为什么我们需要第二个参数[].slice.apply(arguments)?即,为什么不能使用[]代替它? 2. 或者,为什么我们不能完全省略该参数?
非常感谢你帮助我更深入地理解这些问题。
1个回答

1

reduce函数的第二个参数args是必须的,用于指定累加器(即args变量)的初始值,以便在第一次迭代时使用。

fs.reduce((args,f) =>

将初始值传递给.reduce可以使args成为初始参数(正如预期的那样)。否则,如果没有向.reduce传递初始值,则args的初始值将是fns数组中的第一项,这绝对不是您想要的:(保留HTML标签)

function piper(...fs) {
    return (...args) => fs.reduce((args,f) => {
      console.log(args);
      return [f.apply(this,args)];
    })[0];
}

var result = piper(Math.min, Math.abs, Math.sqrt)(16, -9, 0)
// Output result:
console.log(result);

此外,就像这样,fns 数组中的第一个函数根本不会被调用。
通常,只有当累加器的类型与迭代的数组中的项目的类型匹配并且与所需结果的类型匹配时,才会省略 .reduce 的初始值,例如数字操作。

// sum:
const result = [1, 2, 3].reduce((a, b) => a + b);
console.log(result);

当然,如果要迭代的数组可能为空,您还应该提供一个初始值。
在(几乎?)所有其他情况下,为.reduce提供一个初始值是必要的。

1
即使在这种情况下,提供一个初始值为0也是合适的,这样一个空数组在调用reduce()时就不会抛出异常。 - Patrick Roberts

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