Js中函数式编程的理解

函数式编程的理解

函数式编程是一种编程范式,可以理解为是利用函数把运算过程封装起来,通过组合各种函数来计算结果。函数式编程与命令式编程最大的不同其实在于,函数式编程关心数据的映射,命令式编程关心解决问题的步骤。

描述

到近些年,函数式以其优雅,简单的特点开始重新风靡整个编程界,主流语言在设计的时候无一例外都会更多的参考函数式特性Lambda表达式、原生支持map、reduce、...,Java8开始支持函数式编程等等。
在前端领域,我们同样能看到很多函数式编程的影子,ES6中加入了箭头函数,Redux引入Elm思路降低Flux的复杂性,React16.6开始推出React.memo(),使得pure functional components成为可能,16.8开始主推Hook,建议使用pure function进行组件编写等等。

实例

实际上这个概念还是比较抽象的,直接来举一个例子说明,假设我们有一个需求,对数据结构进行更改。

["john-reese", "harold-finch", "sameen-shaw"] // 转换成 [{name: "John Reese"}, {name: "Harold Finch"}, {name: "Sameen Shaw"}]

按照传统的命令式编程的思路,我们通常是使用循环将其进行循环拼接等操作,以得到最终的结果。

const arr = ["john-reese", "harold-finch", "sameen-shaw"]; const newArr = []; for (let i = 0, n = arr.length; i < n ; i++) { let name = arr[i]; let names = name.split("-"); let newName = []; for (let j = 0, neamLen = names.length; j < neamLen; j++) { let nameItem = names[j][0].toUpperCase() + names[j].slice(1); newName.push(nameItem); } newArr.push({ name : newName.join(" ") }); } console.log(newArr); /* [ { name: 'John Reese' }, { name: 'Harold Finch' }, { name: 'Sameen Shaw' } ] */

这样当然能完成任务,但是产生了比较多的中间变量,另外变量名比较多,有比较复杂的逻辑,假如作为一个函数并返回值来处理的话就需要从头到尾读完才能知道整体的逻辑,而且一旦出问题很难定位。
如果我们换一个思路,采用函数式编程的思想来做,我们可以先忽略其中的curry和compose以及map这些函数,之后当我们实现这两个函数后会重现这个示例,当我们只是看这个编程思路,可以清晰看出,函数式编程的思维过程是完全不同的,它的着眼点是函数,而不是过程,它强调的是如何通过函数的组合变换去解决问题,而不是我通过写什么样的语句去解决问题,当你的代码越来越多的时候,这种函数的拆分和组合就会产生出强大的力量。当然下面的例子可以直接在Ramda环境跑,需要将未定义的方法都加上R.作为R对象的方法调用。

const capitalize = x => x[0].toUpperCase() + x.slice(1).toLowerCase(); const genObj = curry((key, x) => { let obj = {}; obj[key] = x; return obj; }) const capitalizeName = compose(join(" "), map(capitalize), split("-")); const convert2Obj = compose(genObj("name"), capitalizeName) const convertName = map(convert2Obj); convertName(["john-reese", "harold-finch", "sameen-shaw"]); 函数式编程

根据学术上函数的定义,函数即是一种描述集合和集合之间的转换关系,输入通过函数都会返回有且只有一个输出值。 所以,函数实际上是一个关系,或者说是一种映射,而这种映射关系是可以组合的,一旦我们知道一个函数的输出类型可以匹配另一个函数的输入,那他们就可以进行组合,就例如上边的compose函数,它实际上就完成了映射关系的组合,把一个数据从String转换成了另一个String然后再转换成Object,实际上类似于数学上的复合运算g°f = g(f(x))。

const convert2Obj = compose(genObj("name"), capitalizeName);

在编程世界中,我们需要处理的其实也只有数据和关系,而关系就是函数,我们所谓的编程工作也不过就是在找一种映射关系,一旦关系找到了,问题就解决了,剩下的事情,就是让数据流过这种关系,然后转换成另一个数据罢了。这其实就是一种类似于流水线的工作,把输入当做原料,把输出当做产品,数据可以不断的从一个函数的输出可以流入另一个函数输入,最后再输出结果。 所以通过这里就可以理解函数式编程其实就是强调在编程过程中把更多的关注点放在如何去构建关系,通过构建一条高效的建流水线,一次解决所有问题,而不是把精力分散在不同的加工厂中来回奔波传递数据。

相关特性 函数是一等公民

函数是一等公民First-Class Functions,这是函数式编程得以实现的前提,因为我们基本的操作都是在操作函数。这个特性意味着函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。

声明式编程

声明式编程Declarative Programming,函数式编程大多时候都是在声明我需要做什么,而非怎么去做,这种编程风格称为 声明式编程,这样有个好处是代码的可读性特别高,因为声明式代码大多都是接近自然语言的,同时它解放了大量的人力,因为它不关心具体的实现,因此它可以把优化能力交给具体的实现,这也方便我们进行分工协作。SQL语句就是声明式的,你无需关心Select语句是如何实现的,不同的数据库会去实现它自己的方法并且优化。React也是声明式的,你只要描述你的UI,接下来状态变化后UI如何更新,是React在运行时帮你处理的,而不是靠你自己去渲染和优化diff算法。

无状态和数据不可变

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydzsp.html