纯函数
纯函数的概念
纯函数:相同的输⼊,永远会得到相同的输出,并且没有任何可观察的副作⽤。
纯函数类似数学中的函数(⽤来描述输⼊和输出的关系),y = f(x)
lodash 是⼀个纯函数功能库,提供了对数组,数字,对象,字符串,函数等的⼀些操作⽅法。
数组的 slice 和 splice 分别是纯函数和不纯的函数
slice 返回数组的指定部分,不会改变原有数组
let array = [1, 2, 3, 4, 6]
console.log(array.slice(0, 3))
console.log(array.slice(0, 3))
console.log(array.slice(0, 3))
多次调⽤并不会有其他结果,对相同的输⼊始终得到相同的输出
splice 对数组进⾏操作,并返回该数组,会改变原有数组。
let array = [1, 2, 3, 4, 6]
console.log(array.splice(0, 3))
console.log(array.splice(0, 3))
console.log(array.splice(0, 3))
⾃⼰写⼀个纯函数其实很简单,对于纯函数来说,必须有输⼊(参数)和输出(返回值)。
function add (a , b){
return a + b
}
函数式编程不会保留计算中间的结果,所以变量是不可变的(⽆状态的)
由于纯函数的特性,我们可以把⼀个函数的结果交给另外⼀个函数处理。(函数组合)
Lodash
使⽤:安装依赖
npm i lodash -save
演示⽅法
first / last / toUpper / reverse / each / includes / find / findIndex
let array = [1, 2, 3, 4, 6]
console.log(array.slice(0, 3))
console.log(array.slice(0, 3))
console.log(array.slice(0, 3))
let array = [1, 2, 3, 4, 6]
console.log(array.splice(0, 3))
console.log(array.splice(0, 3))
console.log(array.splice(0, 3))
function add (a , b){
return a + b
}
除了⼯具函数,还提供了函数柯⾥化和函数组合的⼯具。
纯函数的好处
可缓存
因为对相同的输⼊总有相同的输出,对于⼤量运算过程的函数,可以直接把结果缓存起来。
记忆函数 memoize
模拟记忆函数
const _ = require('lodash')
const array = ['zhangsan', 'lisi', 'wangwu', 'zhaoliu']
console.log(_.first(array)) // zhangsan
console.log(_.last(array)) // zhaoliu
console.log(_.toUpper(_.first(array))) //ZHANSAN
//console.log(array.reverse()) // 没有参数传递,不是纯函数
//console.log(_.reverse(array))
const res = _.each(array, (item, index) => {
console.log(item, index)
})
console.log(res) // 返回值为函数本身
// 在ES6 之前,可以使⽤ includes find 和 findIndex
除了⼯具函数,还提供了函数柯⾥化和函数组合的⼯具。
纯函数的好处
- 可缓存
因为对相同的输⼊总有相同的输出,对于⼤量运算过程的函数,可以直接把结果缓存起来。
记忆函数 memoize
function getArea(r) {
console.log(r)
return Math.PI*r*r
}
let getAreaWithMemory = _.memoize(getArea)
console.log(getAreaWithMemory(2))
console.log(getAreaWithMemory(2))
console.log(getAreaWithMemory(2))
模拟记忆函数
function memoize(fn) {
let cache ={}
return function () {
let key = JSON.stringify(arguments)
cache[key] = cache[key] || fn.apply(this, arguments)
return cache[key]
}
}
let getAreaWithMemory = memoize(getArea)
console.log(getAreaWithMemory(2))
console.log(getAreaWithMemory(2))
- 可测试
让测试变得更为⽅便
单元测试其实在断⾔输出的结果 ,所有的纯函数都是有输⼊有输出,所以有利于测试。 - 并⾏处理
再多线程下,多个线程同时去修改⼀个变量可能会出现意外的情况⽽纯函数是⼀个封闭的空间,它只依赖于参数,不会访问共享的内存数据,所以在并⾏环境下,可以任意的运⾏纯函数。(Web Worker)
副作⽤
/" 不纯的
let mini = 18
function checkAge(age){
return age >0 mini
}
/" 纯函的
function checkAge(age){
let mini = 18 /" 硬编码 可以通过柯⾥化解决
return age >0 mini
}
如果函数依赖于外部的状态就⽆法保证输出相同。会带来副作⽤。
副作⽤的来源:
- 配置⽂件
- 数据库
- ⽤户的输⼊
所有的外部交互都有可能带来副作⽤,副作⽤让⽅法的通⽤性下降,不适合扩展和可重⽤。但是副作⽤
不能完全禁⽌,尽可能控制他们在可控范围内发⽣。