对reduce函数的一些思考

154 阅读4分钟

端午节,在杭州无情的大雨中,一个练习时长两周半的程序员打开了 某教授撰写的某FP书籍,开始了一些低效率的学习。

第六章 -Coding by Composing

谈到了使用compose的方法来实现取一个数组最后一个元素的方法(好 像并不是很厉害):先将数组反转然后取第一个元素.代码如下

    //compose的实现
    // 注:compose方法在这里即为将两个函数组合起来形成一个流水线
    const compose = (f,g) => f(g(x))
    
    //反转数组
    const reverse = reduce( (acc,x) => [x].concat(acc) , [] )
    
    //取数组的第一个元素
    const head = (x) => x[0]
    
    //最终效果
    const last = compose( head , reverse )
    
    last(['a','b','c'])     // 'c'

代码很简单明了,正当本菜鸡打算将它敲进VsCode里时,突然发现作者 貌没有给出reduce的实现呀,转念一想,已经是不知道多少次看过reduce 的实现,然而现在还是忘了该怎么写一个出来,趁着出去剪头发的时间 (。抱歉,还有头发。)好好思考思考这个问题。

reduce函数是一种什么形式的函数呢,平时它一般以数组的prototype上 的函数出现在日常使用中,它是否和数组有一定的关系呢?

我们先看看将一整个数组取反的函数的代码

    const reverse = reduce( (acc,x) => [x].concat(acc) , [] )

reduce函数接收了一个callback函数和一个空数组,并且它还会返回一个 函数,这个函数将接收一个数组,并且将这个数组取反。我们可以观察一 下这个回调函数的形式,它接收两个参数,一个是acc在这里代表的是数组 值得累积,一个是x,在这里代表了具体的一个数组中的元素,它返回了将 这个元素拼接上元素的积累值的结果。这样的reduce函数就成为了一个可以 将一个数组取反的函数,或许对reduce函数了解的少的新手会很困惑(比如 现在的我)。

那么reduce函数在这个过程中做了什么呢?

我们可以将reduce函数看成是一种抽象的量的累积的方法,有两个关键词, 一个是量,一个是累计,他们都不是一种具体的类型,比如数组,数字, 我们可以累计一个数组,也可以累计一系列数字的求和,也可以累计一系 列字符串的拼接。这个函数应该接收一个量,和累计这个量的方法(在此 例中也就是一个数组和一个回调函数),并且返回一个接收一组即将被累 积的元素的集合为参数的函数。

既然已经有了累计这个量的方法,那么reduce做了什么也就很明显,它只 是通过遍历的方法给这个方法提供了它所需要的材料,并且对这个方法产生 的结果进行累计。它所需要的材料通常有上一个数组元素,当前数组元素, 当前数组元素的下标等等,其中最重要的材料,也就是它的累积本质,当前 累积的结果acc,下面给出我对于这个例子的简单实现。

    const reduce = (callback,initial) => (arr) => {
        let acc=initial;
        for (let i = 0; i < arr.length; i++) {
            acc = callback(acc,arr[i]);
        }
        return acc
    }

这样这样的写法对于callback函数的形式有着严格的要求,callback函数 首先是要拿到自己需要的材料,在此例中即为当前的数组元素和此时累积 的情况,并且在callback函数中必须要规定出累积的形式,是数字的相加 还是数组或字符串的拼接,并且将这个累积的结果返回。这样就有了我们 作为这个函数的用户对于reduce函数使用的规定。

那么我们作为用户,我们给出了callback函数,到底给出了什么呢?

我们给出的实际是累积状态从上一个状态到下一个状态的变化规律!

这样一个似曾相识的概念,它不就是Redux中的reducer函数吗? 它接收store之前的state,一个action,然后给出下一个state。

其实这就是reduce的本质,从一个状态到下一个状态的变化规律,我们 在dispatch中指定action的type,就是在指定我们用什么样的方法来 改变累积的结果,只是我们不再累积了,而是直接替换掉原来的state (或许这也是一种累积)。

那么我们之前提出的问题,它和数组有一定的关系吗?没有,数组只是数据 的一种承载形式,数组中的reduce函数只是针对数组的累积规律做出了特定的 优化,reduce函数并不受限于数据是如何储存的,它的本质在于从一个状态 到下一个状态的变化规律,也就是我们作为用户应该给出的。

结语:
    第一次写文章,概念很简单,文笔不好,也许有很多错误,
    希望读者指出