函数式编程学习
概念: 相同的输入,永远得到相同的输出,而且没有任何可观察的副作用
举个例子?:
let arr = [1, 2, 3];
arr.slice(0,3) //=> 1,2,3
arr.splice(0,3) // => 1,2,3
虽然两个函数都返回了[1, 2, 3],但是splice的副作用是arr数组永久的发生了改变,在函数是编程中,我们需要的结果是稳定的,而不是把数据弄得一团糟的函数,这不是我们想要的
再举个例子?:
var minimum = 21;
var checkAge = age => {
return age > minimum
}
// 上面是一个不纯的函数,下面是一个纯的函数
var checkAge = age => {
var minimum = 21;
return age > minimum
}
在第一个函数中,checkAge的结果取决于外部变量minimum的值,引入了外部的环境,从而增加了认知负荷
至此
我们来看看在概念中没有任何可观察的副作用有什么?
概念:副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互
包含但不限于:
- 往数据库中插入记录
- 发送一个http请求
- 可变数据
- 访问系统状态
- .....
当然,并不是说要禁止使用一切副作用,如果函数是和外部事物打交道,那么这一点就无法保证了
回顾
函数的概念: 每一个输入值返回且只返回一个输出值
函数就是数学上的函数,而且是函数式编程的全部,总能根据相同的输入返回相同的输出,总能保证返回同一个结果
好处
函数式编程的好处:
- 可缓存性
- 可移植性(依赖明确,便于观察和理解
- 可测试性
- 引用透明性
- 并行代码(因为纯函数不需要访问共享的内存
柯里化
只传递给函数部分参数,让它返回一个函数来处理剩下的参数
let sayHello = msg => {
return name => {
return msg + ', My name: ' + name
}
}
sayHello('Hello')('毅翔')
加上一个场景来一个柯里化的例子:
初始化一个年龄,再加上一个age去判断是否大于初始化这个年龄
let checkAge = initAge => {
return age => {
return age > initAge
}
}
checkAge(22)(18) // fasle 判断 18 是否大于
Lodash库
在lodash库中使用curry
var _ = require('lodash')
// 判断age1 是否小于 age2
// 首先柯里化一个纯函数
let judge = _.curry((age1, age2) => {
return age1 < age2
})
console.log(judge(1)(2))
// 判断数组arr中是否存在num
let include = _.curry((arr, num) => {
return arr.includes(num)
})
console.log(include([1, 2, 3, 4])(2));
函数组合
let compose = (f, g) => {
return (x) => {
return f(g(x))
}
}
let f = o => o.toUpperCase()
let g = o => o + '!'
compose(f, g)('asd')
最后
我理解的函数式编程是一种思维,是一种理想化的开发,了解函数式编程并不代表你一定会在项目中去使用,在JS开发中,可能会遇到dom操作,http请求,NodeJs中文件读写等等,会遇到很多副作用,参考某位作者,建议在代码中寻找平衡,最大发挥函数式编程的作用,当然也许,你并不需要它
参考
函数式编程GitBook
Noodles SegmentFault 技术周刊 Vol.16 - 浅入浅出 JavaScript 函数式编程
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。