纯函数 {#%E7%BA%AF%E5%87%BD%E6%95%B0}
纯函数的概念 {#%E7%BA%AF%E5%87%BD%E6%95%B0%E7%9A%84%E6%A6%82%E5%BF%B5}
-
纯函数: 相同的输入始终会得到相同的输出,而且没有任何可观察的副作用
- 纯函数就类似数学中的的函数(用来描述输入和输出之间的关系),
y=f(x)
- 纯函数就类似数学中的的函数(用来描述输入和输出之间的关系),
- Lodash 是一个纯函数的功能库,提供了对数组,数字,对象,字符串,函数等操作的一些方法
- 数组的slice和splice分别是纯函数和不纯的函数
slice
返回数组中的指定部分,不会改变原数组splice
对数组进行操作返回该数组,会改变原数组
- 函数式编程不会保留计算中的结果,所以变量是不可变的(无状态)
- 我们可以把一个函数的执行结果交给另一个函数去处理
多次调用 slice 发现相同的输入得到相同的输出,所以是纯函数, splice 多次调用之后相同的输入输出结果不一致,splice
改变了原数组,所以splice
不是纯函数
let array = [1, 2, 3, 4, 5,]
// 纯函数
console.log(array.slice(0, 3))// 1, 2, 3
console.log(array.slice(0, 3))// 1, 2, 3
console.log(array.slice(0, 3))// 1, 2, 3
`// 不纯的函数
console.log(array.splice(0, 3))// 1, 2, 3
console.log(array.splice(0, 3))// 4, 5
console.log(array.splice(0, 3))// []
`
写一个纯函数
let add = function (n1, n2) {
return n1 + n2
}
`console.log(add(1, 2))// 3
console.log(add(1, 2))// 3
console.log(add(1, 2))// 3
console.log(add(1, 2))// 3
`
Lodash 介绍 {#lodash-%E4%BB%8B%E7%BB%8D}
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。Lodash 中提供了很多方法
chunk
:将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。- 参数1:
array
需要处理的数组 - 参数2:
size
每个分块的长度
- 参数1:
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
`_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
`
compact
去除数组元素中的假值false
,null
,0
,""
,undefined
, 和NaN
都是被认为是"假值"- 参数1:
array
- 参数1:
_.compact([0, 1, false, 2, '', 3]);
// => [1, 2, 3]
concat
: 创建一个新数组,将array
与任何数组 或 值连接在一起- 参数1:
array
被连接的数组 - 参数n:
[values]
连接的值
- 参数1:
var array = [1];
var other = _.concat(array, 2, [3], [[4]]);
console.log(other);
// =\> \[1, 2, 3, \[4\]\]
`console.log(array);
// => [1]
`
memoize
: 建一个会缓存 func 结果的函数。 如果提供了 resolver ,就用 resolver 的返回值作为 key 缓存函数的结果。 默认情况下用第一个参数作为缓存的 key。 func 在调用时 this 会绑定在缓存函数上。- 参数1:
fucntion
需要缓存的函数 - 参数2:
key
这个函数的返回值作为缓存的 key。
- 参数1:
const _ = require('lodash')
// 求圆的面积
function getArea (r) {
console.log(r)
return Math.PI \* r \* r
}
let getAreaWithMemory = _.memoize(getArea)
`console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))
`
curry
: 创建一个函数,该函数接收func
的参数,要么调用func
返回的结果,如果func
所需参数已经提供,则直接返回func
所执行的结果。或返回一个函数,接受余下的func
参数的函数,可以使用func.length
强制需要累积的参数个数。funciton
用来柯里化(curry)的函数arg
需要提供给func
的参数数量。
var abc = function(a, b, c) {
return [a, b, c];
};
var curried = _.curry(abc);
curried(1)(2)(3);
// =\> \[1, 2, 3\]
curried(1, 2)(3);
// =\> \[1, 2, 3\]
curried(1, 2, 3);
// =\> \[1, 2, 3\]
`// Curried with placeholders.
curried(1)(_, 3)(2);
// => [1, 2, 3]
`
纯函数的好处 {#%E7%BA%AF%E5%87%BD%E6%95%B0%E7%9A%84%E5%A5%BD%E5%A4%84}
-
可缓存
- 因为纯函数对相同的输入始终得到相同的输出,所以可以把纯函数的结果缓存起来
-
可测试
- 纯函数让测试跟方便
-
并行处理
- 在多线程环境下并行操作共享内存数据可能出现意外情况
- 纯函数不需要访问共享内存数据,所以在并行环境下可以任意运行纯函数(web Worker )
副作用 {#%E5%89%AF%E4%BD%9C%E7%94%A8}
副作用让一个函数变得不纯,纯函数根据相同的输入返回相同的输出,如果函数一类与外部的状态就无法保证输出相同,就会带来副作用
副作用来源
- 配置文件
- 数据库
- 获取用户的输入
- ...
所有的外部交互都有可能带来副作用,副作用也使得方法通用性会下降不适合扩展和可重用性,同时副作用会给程序带来安全隐患和不确定性,但是副作用也不可能完全禁止,尽可能控制在可控范围内