函数式编程

语义

  • 从本身定义的角度

函数式编程的理论基础来自于数学建模,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算。因此函数式编程就是对数学表达式的抽象。这和自动化系统中方框图的数学抽象不谋而合。

  • 从代码结构的角度

函数式编程范式只有函数的调用,没有for循环、if语句…,代码中看到的只有函数,而程序背后的执行过程被隐藏(引用透明性)。

函数

语义函数就是过程的封装。

函数的特性

关键点函数是对具体功能的抽象。具体的功能抽象映射为函数的作用域、输入、输出、逻辑过程、启动执行。
函数式编程 - 图1

  1. //这个例子虽然使用了高阶函数,但是只是利用了函数的封装性,foo()函数本身并没有功能。
  2. function foo(a, b , fn) {
  3. return fn(a , b);
  4. }
  5. function sum(a , b){
  6. return a + b;
  7. }

引用透明性

语义给定一个函数的输入,有确定不变的输出,说明函数不依赖外部的状态。此时这个函数可以看成一个黑盒子,忽略里面的实现细节。
关键点纯函数就具有透明性。具有透明性、确定输入的函数,可以使用使用缓存,没必要再次执行,避免开销。
例子
函数式编程 - 图2

//模拟数学表达式y = (x + 1) * 2。在计算机中自变量x只有有限个离散值,将x看成数组。
var a = function (num1) {
  return num1++;
}
var b = function (num2) {
  return num2 * 2;
}

var res = b(a(1));    //表示输入1,经过两个函数,输出res

//这里的关键点就是如果函数a的参数1,不是指定的,而是在函数b内指定值,又因为函数a是纯函数,完全可以将函数a看成一个值。
var b = function (a, val) { 
  return a(val) * 5;
}
var res = b(a, 1);

纯函数

关键点函数只依赖参数,并且执行过程中没有副作用。
关键点在你的程序中更多的使用纯函数,那么程序的测试、调试会非常方便。
关键点如果函数的参数是引用类型,就与外部变量有依赖,在函数内部就不能改变这个参数,但是可以读取参数的值。解决方法:对参数克隆。

var a = 1;
function foo(val){
    return val + a;
}
foo(1); //2
//函数foo就不是纯函数,因为依赖外部变量a。如果单独把函数提出来看,在不知道变量a的情况下,输出值是不可预测的。

高阶函数

语义一个函数的参数中中有函数参数或者返回值是函数,这个函数就是高阶函数。这样做的目的就是从过程的角度来看,对函数进行扩展,而不单单只是值的扩展。

函数参数在高阶函数中不同的功能

部分执行过程的替换:函数参数插入高阶函数的执行过程。
结果:函数参数负责处理高阶函数执行结果,是相互依赖的过程。

curring柯里化

把多参数函数重构为每次接收一个参数,将余下的参数作为返回的函数的参数,直到它收到所有的参数并最终求值。

function add(a, b, c, d) {
  return a + b + c + d;
}

function curry(fn) {
  const _arg = Array.prototype.slice.call(arguments, 1);


  return function () {
    const arg = [..._arg, ...arguments];
    return fn.apply(null, arg)
  }
}
console.log(curry(add, 1, 2)(3, 5))

参考

https://www.youtube.com/watch?v=66K9ZxZM64Q&t=1348s 关于函数式编程的理念讲的很好
https://zhuanlan.zhihu.com/p/133851969 函数式编程最基本概念