函数式编程
语义
- 从本身定义的角度
函数式编程的理论基础来自于数学建模,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算。因此函数式编程就是对数学表达式的抽象。这和自动化系统中方框图的数学抽象不谋而合。
- 从代码结构的角度
函数式编程范式只有函数的调用,没有for循环、if语句…,代码中看到的只有函数,而程序背后的执行过程被隐藏(引用透明性)。
函数
函数的特性
关键点函数是对具体功能的抽象。具体的功能抽象映射为函数的作用域、输入、输出、逻辑过程、启动执行。
//这个例子虽然使用了高阶函数,但是只是利用了函数的封装性,foo()函数本身并没有功能。
function foo(a, b , fn) {
return fn(a , b);
}
function sum(a , b){
return a + b;
}
引用透明性
语义给定一个函数的输入,有确定不变的输出,说明函数不依赖外部的状态。此时这个函数可以看成一个黑盒子,忽略里面的实现细节。
关键点纯函数就具有透明性。具有透明性、确定输入的函数,可以使用使用缓存,没必要再次执行,避免开销。
例子
//模拟数学表达式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 函数式编程最基本概念