函数式思维(二)-- 为何你想不到用 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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- EOS DDOS攻击,你想不到的这12小时
- 90%的项目经理都想不到,沟通成本原来可以这么小
- 只有想不到,「99」种扩展Jupyter功能的好方法
- 没想到吧!竟有你绝对想不到的黑客追踪神技术
- 最难学的十大编程语言,Java只排第三,第一你绝对想不到!
- 你绝对想不到年过40岁的程序员可以有多么牛X!,程序员出路
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)
刘长龙 / 电子工业出版社 / 2019-1 / 99
也许你听说过全栈工程师,他们善于设计系统架构,精通数据库建模、通用网络协议、后端并发处理、前端界面设计,在学术研究或工程项目上能独当一面。通过对Python 3及相关Web框架的学习和实践,你就可以成为这样的全能型人才。 《Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)》分为3篇:上篇是Python基础,带领初学者实践Python开发环境,掌握......一起来看看 《Python高效开发实战——Django、Tornado、Flask、Twisted(第2版)》 这本书的介绍吧!