Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up55.[函数式编程] 不用循环的 JavaScript #59
Comments
|
很强! |
|
搭车,安利一篇我的知乎回答:JavaScript 函数式编程存在性能问题么? |
|
再次遇见@justjavac前辈大神 |
|
推荐lodash、ramda,数据结构转换超级方便,基本上不用自己写转换逻辑,理清思路找API就行了。 |
|
哇!惊现学长@rccoder |
函数式编程reduce、map、filter、find等应用实践// 输入为state和originData变量
// 输出为:
{
houseTypeShared: '2居_3居',
houseTypeWhole: '2居',
};
// state和originData变量如下:
// state
const state = {
sharedRooms: { 0: false, 1: true, 2:true },
wholeRooms: { 2: false, 3: true },
};
// 源数据
const originData = {
sharedRooms: [
{
unique: true,
text: '不限',
value: 'UNLIMITED',
},
{
text: '2居',
value: 'TWO',
},
{
text: '3居',
value: 'THREE',
},
{
text: '3居+',
value: 'THREE_MORE',
},
],
wholeRooms: [
{
unique: true,
text: '不限',
value: 'UNLIMITED',
},
{
text: '1居',
value: 'ONE',
},
{
text: '2居',
value: 'TWO',
},
{
text: '2居+',
value: 'TWO_MORE',
},
]
};
// 利用map, reduce, filter等函数式方法,计算出结果。
/*
好处:
1.代码精简
2.map,reduce,filter等方法更具语义化
坏处:
1.初次阅读,难以阅读理解(其实写习惯,就很容易理解了)
*/
const TypeMapParamKey = {
sharedRooms: 'houseTypeShared',
wholeRooms: 'houseTypeWhole',
};
Object.keys(state)
.map(type => {
const rtText = Object.keys(state[type])
.filter(index => state[type][index])
.map(index => originData[type][index].text)
.reduce((rt, text, index) =>
(`${rt}` + (index === 0 ? '' : '_') + `${text}`),
'',
);
return {
[TypeMapParamKey[type]]: rtText,
};
})
.reduce((rt, item) => Object.assign(rt, item), {}) |

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

不用循环的 JavaScript -- 函数式编程
通过代码一步步的深入
mapreducefilterfind...循环 Loop
先看看js中的基础循环代码
while使用
while循环来大写数组中每个元素这种循环太常见了,一个初始值为0计数器
i,每次循环需要递增i的值,并通过len来判断循环终止条件。简单的
for循环代码如下:比起
whilefor循环把计数器i放在循环顶部,避免了while中忘记计数器自增自增而引起的死循环。但是后退一步看,我们只是要把每一项大写,但是并不在乎循环中的计数器
i因为这种对数组每一项进行循环操作的模式很常见,所以有了 ES2015 中的
for..of循环用了
for...of省了计数器和循环终止的判断,也不需要抽取出数组每一项来处理映射 Mapping
虽然
for...of更简洁,但还是要初始newCompany并执行push如何做到更加精简
如果现在有两个数组需要
capitalize呢两次循环 简单粗暴:
这看起来不是很 DRY (Don't repeat yourself) ,所以可以重构下
这样看起来还行,但是如果新加一个功能,只是首字母大写呢
如果这样写,下面的代码依然不是很 DRY
那就继续重构,抽象成给定一个数组和一个函数,然后将数组中每一项映射到新的数组的模式
但代码里依然有个循环,只能写成递归的形式
递归的代码极简,但在旧浏览器里有性能问题,所以我们就直接用 js 内置的
map好了同样简单粗暴
像函数式编程一样,分而治之,两个用来做大写字符串的函数只关注本身的功能,不关心数据从哪来;同时
map只负责传递函数,不关心函数是干什么的。Reduce
map在输出和输入的相同长度的数组上很好用。但是如果再添加一个数字数组或者在一个 list 中找出最短的字符串呢。
如下,有个 worker 的数组,包含姓名和薪水
找出 salary 最高的那位
上面的代码那样写也没什么问题。为了深入一点,我们现在需要所有人 salary 的总和,代码如下
上面两个例子中都需要在循环之前定义一个变量,然后在每次循环中处理一个循环项后并更新这个变量。
为了深入理解这个循环,我们把循环内部拆解为函数,找出相似之处
上面的代码两个循环非常相似,唯一不同的是初始值和循环中的调用的函数。两者都将数组最终降为单个值,所以我们自己写
reduce但是 js 里面内置了
reduce,我们直接拿来用就行了使用了原生的
reduce分离了循环代码后,代码的复杂度降低了很多。Filter
map可以很好的处理数组的每一项reduce可以把一个数组缩减到一个单一值但是想处理一个数组中的多个项目呢?首先给
workers数组加点数据两个问题:
用个普通的
for循环:上面两块代码唯一不同的是
if判断,所以把if转换成函数我们在把这种只返回
truefalse的函数成为predicate(谓词函数) 然后使用predicate来决定数组中元素是否保留把
predicate函数抽象到一个 filter 中同样 js 也内置了
filter函数,直接使用只需要写一个功能单一而专注的过滤函数,然后调用
filter即可。Find
如果需要找出 Sara ,
filter是没问题的这样的代码并不高效,因为只有一个 Sara ,找到后就可以停止查找操作了。
所以写一个
find函数, 返回第一个符合项find函数实现非常简单,js 也内置了find和
filter一样,代码简洁且专注。最后
使用内置的这些迭代函数
mapreducefilterfind在上面每一个例子中,我们把问题分解,使用更小而纯粹的函数即可找到解决方案。
因为循环中总是在处理或者构建一个数组,或者两者同时在做,因此通过 js 内置的数组处理函数几乎可以消除代码中绝大多数循环,写出复杂性更低更利于维护的代码。