让前端飞Web前端之路

函数式编程概述

2019-12-07  本文已影响0人  子皙丶

1. 函数式编程的大概背景

2. 纯函数的定义

对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不用依赖外部环境的状态。

举个栗子:
在Js中,对于数组的操作有些是纯的,有些不是纯的。

var arr =  [1,2,3,4,5]

 //纯函数
arr.slice(0,3)  // result : [1,2,3]
arr.slice(0,3)  // result : [1,2,3]

//非纯函数
arr.splice(0,3)  //  result : [1,2,3]
arr.splice(0,3)  // result : [4,5] 
  • 多次调用传入的参数相同会得到相同的结果
  • 闭关锁国,不受外部的影响

3. 函数式编程为何排斥不纯的函数

非纯函数中,函数的行为需要由外部的系统环境决定,也就是说此函数行为不仅取决于输入的参数,还取决与外部的变量。

举个栗子:

 var timeOfLife = 20
 //纯函数
function test(){
  return age > 20
}
//非纯函数
function test(){
  return age > timeOfLife
}

非纯函数中受外部变量timeOflife的影响,这种对于外部状态的依赖,是造成系统复杂性大大提高的主要原因。
如何解决呢?

4. 函数柯里化

向函数传递一部分参数来调用塔,让它返回一个函数去处理剩下的参数。

注:事实上柯里化是一种“预加载”函数的方法,通过传递较少的参数,得到一个已经记住了这些参数的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法。

解决上述代码中的问题:

var timeOflife = 20
function test(timeOflife){
  return function(age){
    return age > timeOflife
  }
}
var testing = test(20)
testing(18)  // result : false

5. 函数组合

为了避免写出不优雅的包菜式的代码,例如:h(g(f(x))),我们需要用到函数组合

定义N个纯函数,像拼积木一样优雅的将N个函数组合起来。

举个栗子:

var compose = function(f,g){
  return function(x){
    return f(g(x))
  }
}

var mult = function(x){
  return x * 5
}

var add = function(x){
  return x + 1
}

compose(mult,add)(2)   // result : 15
  • 定义两个纯函数 mult 和 add
  • 使用组合函数的方式,将两个纯函数组合成compose,对外调用compose就可以显示功能。

6. 声明式和命令式

通过编写一条有一条的命令,让计算机执行一些动作,其中一般会涉及许多繁杂的细节。一般初级编程人员编码时使用比较多。

举个栗子:

var rest = []
var arr = [4,9,16,25]
for(var i = 0 ; i < arr.length ; i++){
  if(rest.indexOf(arr[i]) === -1){
    rest.push(Math.sqrt(arr[i]))
  }
}

函数的目的就是将arr数组中的数据开方放到rest中去,但是用命令式的代码就会发现,代码复杂不易理解,也不够优雅。

通过写表达式的方式,声明我们想干什么,而不是通过一步步的指示。声明式代码,相比较函数式编程的一个明显的好处-- 编写简洁、结构优雅、优化代码时更能专注、业务和功能能够分离。

举个栗子:

var arr = [4,9,16,25]
var rest = arr.map(Math.sqrt)

7. 总结

  • 函数对于外部状态的依赖,是造成系统复杂性大大提高的主要原因。
  • 代码书写中让函数尽可能的纯净。(也就是我们上面说的写纯函数,然后使用组合的方式,将纯函数组合起来已达到实现功能的目的)
  • 函数式编程不是万能的,它与OOP一样,只是一种编程规范
  • 为降低软件复杂度,OOP的方式是靠良好的封装、继承、多态、以及接口定义。函数式编程则是靠组合、柯里化等技术。

简而言之:函数式编程就是通过柯里化、组合等技术将纯函数灵活运用已达到实现功能的目的。

上一篇下一篇

猜你喜欢

热点阅读