函数式编程入门

什么是函数式编程

函数式编程,个人理解是在编写纯函数。

据印度Anto Aravinth的解释的函数式编程是一种范式,我们能依靠这种范式创建仅依赖输入就可以完成自身逻辑的函数。

而这种函数就是我所理解的纯函数。

纯函数特点

  • 同样的输入,输出一定相同
  • 函数不会改变任何外部环境的变量

函数式编程的引用透明性

即所有函数对于相同输入都返回相同的值,那么据此产生了一个术语,叫替换模型,即把一个函数的调用用它的返回值替换,这将带来可以缓存的代码,当函数调用以后,我们将它的返回值存在内存里(比如用一个对象的属性存起来),下次使用就直接取对象这个属性映射的值。

并发优势

  • 在并发层面上,由于函数不会对外部环境变量进行修改,只依赖传入的参数,所以,并发执行两个或多个一样的函数时相互之间不会受到影响

抽象与高阶函数

抽象

  • 个人总结维基百科的表述,抽象即是一种管理复杂度的方法,把复杂度限定到你能处理的范围。这个范围层面的确定即是一种抽象。
  • 比如高级程序语言就是一种抽象,它的底层是复杂的汇编语言以及机器语言,然而你把它抽象出来进行问题的处理,而不考虑底层复杂的调用和实现
  • 抽象使我们关注预定的目标而不去考虑底层的细节实现

高阶函数

  • 高阶函数就是接受函数作为参数并且/或者返回函数作为输出的函数
  • 经常用到的比如map,forEach等

高阶函数的思维

  • 高阶函数是一种声明式的抽象,声明式即研究“做什么”而不是“如何做”,而抽象使问题关注的地方更加单一,简单化
  • 比如forEach函数抽象出了遍历数组这个过程,我们不用去关心如何去做遍历,而是专注于对每次遍历的结果的操作

柯里化

一元函数与多元函数

  • 只接受一个参数的函数叫一元函数,可以以此类推,几元函数就是接受几个参数的函数

变参函数

  • 函数接受的参数不确定的函数叫做变参函数(比如使用arguments)
1
2
3
4
5
6
7
/**
* 变参函数
*/
function vary(...args) {
console.log(args)
//do something to args
}

柯里化思想

  • 所谓柯里化就是把多参函数转化为嵌套的单参函数

currying的一种实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 将多参函数转换为单参函数的一种实现
* @params fn 需要转化的多参函数
*/
function curry(fn) {
//异常处理
if (typeof fn !== 'function') {
throw new Error('fn is not a function')
}
//转换处理
return function curryInner(...args) => {
//当传入函数的参数数目大于返回curryInner的参数长度时
if (fn.length > args.length){
return function() {
return curryInner.apply(null, args.concat([].slice.call(arguments)))
}
}
return fn.apply(null, args);
}
}

分析举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 测试函数作为实参传递
* @params x, y, z
*/
function foo(x, y, z) {
// do something
}

const curriedFn = curry(foo);
/**
* 此时curriedFn为
* function curryInner(...args) => {
* if (fn.length > args.length){
* return function() {
* return curryInner.apply(null, args.concat([].slice.call(arguments)))
* }
* }
* return fn.apply(null, args)
* }
*/

//调用并传入实参1, 2 ,3
curriedFn(1)(2)(3)
  • 当执行到curriedFn(1)时,因为args.length为1,fn.length为3所以进入if块将args的参数连接,此时args.length为2

  • 上一步返回的还是curryInner函数,再执行curriedFn(1)(2),此时由于args.length为2还是小于3,再重复上述步骤执行curriedFn(1)(2)(3)

  • 此时args.length为3,if条件不满足,执行fn.apply(null, args),即相当于执行了foo(1,2,3)

文献参考:

《JavaScript ES6 函数式编程入门经典》 【印】Anto Aravinth 著 梁宵 译


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏