理解函数式编程

Posted 异或

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解函数式编程相关的知识,希望对你有一定的参考价值。

函数式编程是什么

函数式编程,一个很早的概念,它的出现更是早于面向对象式编程。面向对象式编程,主要在于将现实世界跟计算机做映射,将现实的世界抽象到计算机中,便于我们理解和写出高质量的代码。那为什么还要有函数式编程呢。函数式编程的思维方式是把现实世界的事物和事物之间的联系抽象到程序世界。是不是听起来太抽象了,实际上在我看来,函数式编程就是尽可能的把每个功能拆分成一个个函数,更多强调的是函数之间的关系,比如

y = f(x)这种映射关系,然后通过函数之间的不断组合,产生更多的函数。

闭包

说到函数式编程,就要来说说闭包了,闭包是javascript函数式编程的支持。面试官经常会问闭包是什么,实际上大多数面试者也知道闭包是什么,但要转换成正式一点的语言就经常有点说不清了。

闭包:函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包。

也就是可以在另外一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员。

function makeSay() { const msg = 'Hello' return function() { console.log(msg) }}const say = makeSay()say() // Hello

拿上面代码案例来讲,就是makeSay这个函数已经执行完了,按道理应该里面的变量都要被清除引用。但是因为函数里面的匿名函数保留了对msg的引用,所以导致msg变量不会被清除,匿名函数依然可以访问到这个变量,这就形成了闭包。

纯函数

纯函数,顾名思义,就是很单纯。。。纯到什么程度呢,就是对于一个函数来说,我们输入什么,对应就输出什么,一个输入,输出的结果永远是确定的。就像高中数学学的一对一的关系。

function sum(a, b) { return a + b}sum(1, 2)sum(1, 2)sum(1, 2) // 无论函数执行几次,对应相同的输入永远得到相同的输出

副作用

副作用,可以让一个函数变得不纯。怎么不纯呢。就是一个输入,输出的结果却不一定。什么情况会发生这种情况:当一个函数依赖于外部的状态,比如配置文件,数据库,用户的输入这些,都有可能带来副作用,导致函数不纯。但是这种情况我们能禁止吗。答案是不能的,只能通过编码,尽可能控制它们在一个可控范围内发生。这就好比错误,是人都会犯错误。我们不可能不犯错,但我们可以通过自己不断的积累,降低犯错的几率。

let a = 14function sumValue(b) { return a + b}sumValue(2) // 16a = 15sumValue(2) // 17

柯里化

先借用下维基百科对于柯里化的解释,后面再说出我的理解,这样才能完全看懂这个词的概念

数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。

函数柯里化说白了就是对参数进行降解,你本来需要三个参数,现在把两个参数先保存起来,然后你调用的时候只需要传一个参数。保存起来就是我们前面说的使用闭包。

function makeMsgFn(type) { return function(msg) { if (type === 'success') { console.log(msg) } else { console.error(msg) } }}const successMsg = makeMsgFn('success')const errorMsg = makeMsgFn('error')

从这里看就有点透漏出函数式编程的本质了,对于基本的函数进行抽象,通过函数之间的组合,实现更复杂的函数。

函数组合

不知道你有没有用过linux的管道操作符|,函数组合就跟管道一样,我们把复杂的函数抽象成一个个基本的功能函数,每个函数只完成一个功能。然后我们利用管道连接起来,构成一个复杂的函数。

# 将 ls 命令的输出发送到 grep 命令,作为 grep命令的输入
ls | grep log.txt

比如,我们实现一个获取数组最后一个(实际绝对不会这样做...)的函数。先说明下,因为我们利用管道进行组合,一个函数的输入就是另外一个函数的输出,所以我们要确保函数只传一个参数。这个时候可以利用函数柯里化。

function first (arr) { return arr[0]}function reverse (arr) { return arr.reverse()}const arr = [1,2,3,4]reverse(first(arr)) // 4

你可能会想,这样写会很清晰吗,这么多括号,看着都晕。emmmmm。确实是这样的,不过你可能觉察到了什么。是的,我们可以封装成一个函数。

function compose(fn, sn) { return function(x) { return fn(sn(x)) }}const getLastOfArray = compose(first, reverse)getLastOfArray([1, 2, 3, 4]) // 4

what,大哥,你这是封装吗,这不是就套个外壳吗?

以上是关于理解函数式编程的主要内容,如果未能解决你的问题,请参考以下文章

理解函数式编程

函数式编程/命令式编程

深入理解函数式编程一种基于Consumer和Builder的OkHttp函数式编程方法

每日一题谈谈你对函数式编程的理解?

《On Java 8》中文版 第十三章 函数式编程

学会JavaScript函数式编程(第1部分)