相关文章
【函数式编程】基于JS 进行函数式编程(一)引入 | 什么是函数式编程 | 函数式编程的优点
【函数式编程】基于JS进行函数式编程(二)高阶函数 | 函数代替数据传递 | 函数是一等公民 | 闭包 | 使用高阶函数实现抽象 | 数组的高阶函数
【函数式编程】基于JS进行函数式编程(三)柯里化 | 偏函数 | 组合与管道
【函数式编程】基于JS进行函数式编程(四)函子 | MayBe函子 | Monad函子
什么是函数式编程
引入
概念
我们知道,在数学中,函数可以有如下形式:
f(X) = Y
,即一个函数f ,以X作参数,返回输出结果Y。
据此,我们可以归纳一个函数:
- 函数必须接受一个参数
- 函数必须返回一个值
函数应该根据接收到的参数(如:X)运行,而不是外部参数/环境
(关键)对于一个给定的X,只会输出唯一的一个Y
(关键)
在编程语言中,函数式编程是一种范式,其能够创建仅依赖输入就可以完成自身逻辑的函数。这保证了当函数被多次调用时仍然返回相同的结果。同时,函数不会改变任何外部环境变量,这也将产生可缓存、可测试的代码。
函数与方法
- 函数:一段可以通过其名称被调用的代码。它可以传递参数并返回值。
- 方法:一段必须通过
其名称及其关联对象的名称被调用
的代码。例如,在对象中定义的函数,就是该对象的方法。
引用透明性
前面我们提到: 对于一个给定的X,只会输出唯一的一个Y
。即所有的函数,对于相同的输入,将返回相同的值。这一性质被称为引用透明性
。
这使得并发代码
和缓存
成为可能。因为,具有引用透明性的函数,只能依赖来自参数的输入
,我们可以轻松地用多线程运行这样的代码,没有任何锁机制。
编程范式之 命令式 与 声明式
首先我们要理解什么是命令式,什么是声明式。
- 命令式:告诉编译器
该做什么
。即就告诉编辑器“如何做“
。如下,这段代码告诉编译器”获取数组长度,循环数组,用索引获取每一个数组元素“。
let array = [1,2,3]; for(i=0;i<array.length;i++) console.log(array[i]);
- 声明式:告诉编译器
“做什么”
。如何做的部分,将被抽象到普通函数(也称”高阶函数,如forEach()“)中。如下代码,我们使用声明式方式改写上面的命令式代码。
let array = [1,2,3]; array.forEach((e)=>console.log(e);)
由此可见,声明式让开发者只需要关注”做什么“
部分。而无需关心怎么做。
函数式编程的优点
纯函数
大多数函数式编程的好处来自编写纯函数。
定义: 对给定的输入返回相同的输出的函数。
例如:
let double = (value) => value*2 ;
这是一个简单的纯函数,我们给它一个输入,它返回相同的输出。
可见,纯函数遵循”引用透明性“
。
同时,纯函数不应该改变任何外部环境变量
,即纯函数不依赖任何外部变量。
并发代码
纯函数总是允许我们并发执行代码。因为纯函数不会改变它的环境,这意味这我们不需要担心同步问题。
例如:
let global = "something"; let func1 = (input) => {global="something2";} let func2 = () => {if(global==="something2"){}}
改写:
let func1 = (input,global) => {global="something2";} let func2 = (global) => {if(global==="something2"){}} //将global变量作为参数,由此可不依赖外部变量
可缓存
纯函数总是为给定输入返回相同的输出,那么就可以对输出进行缓存。
由此可见,纯函数只专注做一件事!