函数式思维(二)-- 为何你想不到用 reduce

栏目: JavaScript · 发布时间: 6年前

内容简介:上次我写了一篇简单介绍函数式思维的文章,我们组的同学看了之后表示很感兴趣,希望我有空多写写这方面的内容,然后表示他能想到用数组的 map,但是想不到 reduce。我想这可能也是个普遍现象,因为在对 FP(函数式编程)接触不多的同学来讲,脑海中对 map 的印象,可能基本等同于循环,而对 reduce 就相对陌生。但其实呢,reduce 是个比 map、flatMap 啥的更通用的函数,你可以用 reduce 轻易地实现其他函数。我们先实现一下 reduce:JS 里

上次我写了一篇简单介绍函数式思维的文章,我们组的同学看了之后表示很感兴趣,希望我有空多写写这方面的内容,然后表示他能想到用数组的 map,但是想不到 reduce。我想这可能也是个普遍现象,因为在对 FP(函数式编程)接触不多的同学来讲,脑海中对 map 的印象,可能基本等同于循环,而对 reduce 就相对陌生。但其实呢,reduce 是个比 map、flatMap 啥的更通用的函数,你可以用 reduce 轻易地实现其他函数。

我们先实现一下 reduce:

// foldl
const reduce = (reducer, acc) => arr => {
    // reduceRight: const x = arr.pop();
    const x = arr.shift();
    if (!x) return acc;

    return reduce(reducer, reducer(acc, x))(arr);
};
复制代码

JS 里 Array.prototype.reduce 跟我这个稍有不同,它的 reducer 可以接收四个参数(比我的版本多了 currentIndex 和 array),某种程度上我的实现更 FP 一点,有 currentIndex 这个参数,基本就告诉我们它的实现是通过循环做的,而且这多出来的两个参数在什么场景下会真的必须用到呢?我想是在你 reduce 的过程中还在改变原数组的情况下,所以需要从参数拿到更新后的 array(也就意味着产生了副作用),这本身就很不 FP,不可变性和无副作用是 FP 的重要特性,就算我们在真实开发中无法完全做到,但既然是在谈 reduce,那总该尽量避免。所以个人感觉 JS 的这个 reduce 从 FP 的角度看的话有点不伦不类。

然后再解释下为啥我的 reduce 不是直接接收三个参数,而要用部分应用的形式,先接收两个,返回一个接收一个参数的函数呢?是为了复用,我们看个例子,用 reduce 实现一个 sum 函数,把数组里的元素都累加起来:

const arr = [1, 2, 3]; // 下文所有的 arr 都是这个

const sum = reduce((acc, x) => acc + x, 0);
sum(arr); // => 6
复制代码

reduce 在接收不同的 reducer 和 acc 的时候会返回不同的函数,这里是返回 sum,是不是就很顺。而如果 reduce 是一个接收三个参数的函数,那 sum 就得是 const sum = (arr) => reduce((acc, x) => acc + x, 0, arr) ,也不是不可以,但比较丑陋。

接下来我们用 reduce 实现数组的其他方法:length、map、flatMap、includes、find

// JS 的 Array.length 跟我这个实现不一样,
// arr[100] = 1,arr.length 就为 101 了,因为 JS 的 Array 本质是对象
const length = reduce(acc => acc + 1, 0);
length(arr); // => 3

const map = func => reduce((acc, x) => [...acc, func(x)], []);
map(x => x + 1)(arr); // => [2, 3, 4]

const flatMap = func => reduce((acc, x) => [...acc, ...func(x)], []);
flatMap(x => [x + 1])(arr); // => [2, 3, 4]

const includes = element => reduce((acc, x) => acc || (x === element), false);
includes(1)(arr); // => true

// 找到第一个符合条件的元素返回,否则返回 undefined
const find = func => reduce((acc, x) => acc || (func(x) ? x : undefined), undefined);
find(x => x > 2)(arr); // => 3
复制代码

我们有时候处理字符串,也会想用到 reduce、map 啥的,那我们就给 String.prototype 加上:

// string
String.prototype.reduce = function (reducer, acc) {
    return reduce(reducer, acc)(this.split(''));
};

String.prototype.map = function (func) {
    return map(func)(this.split('')).join('');
};

const str = '123';
str.reduce((acc, x) => acc + Number(x), 0); // => 6
str.map(x => Number(x) + 1); // => '234'
复制代码

emmmmmmm……就这样吧。


以上所述就是小编给大家介绍的《函数式思维(二)-- 为何你想不到用 reduce》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

电子商务:管理与社交网络视角(原书第7版)

电子商务:管理与社交网络视角(原书第7版)

(美)埃弗雷姆·特班(Efraim Turban)、戴维.金(David King)、李在奎、梁定澎、德博拉·特班(Deborrah Turban) / 时启亮、陈育君、占丽 / 机械工业出版社 / 2014-1-1 / 79.00元

本书对电子学习、电子政务、基于web的供应链、协同商务等专题进行了详细的介绍,全书涵盖丰富的资料以及个案,讨论了Web 2.0环境内的产业结构、竞争变化以及对当今社会的影响。另外,本书在消费者行为、协同商务、网络安全、网络交易及客户管理管理、电子商务策略等内容上都有最新的改编,提供读者最新颖的内容,贴近当代电子商务的现实。 本书适合高等院校电子商务及相关专业的本科生、研究生及MBA学员,也可......一起来看看 《电子商务:管理与社交网络视角(原书第7版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具