1.为什么要学函数式编程
1.函数式编程事随着react 的流行受到越来越多的关注
2.Vue3 也开始使用函数式编程
3.函数式编程可以抛弃this
4.打包过程中可以更好的利用 tree shanking 过滤无用代码
5.方便测试,使代码更灵活,重复使用函数
6.很多库帮助我们进行函数式开发 lodash randa等
2.什么事函数式编程
函数式编程(Function Programming, FP) FP 是编程的范式之一
- 面向对象编程的思维方式: 把现实世界的事物抽象成 => 程序世界中的类和对象,通过封装,继承和多态来演示事物和事物之间的联系
- 函数式编程的思维方式:把现实世界的事物和事物之间的 联系 抽象到程序世界
// 非函数式
let num1 = 1
let num2 = 2
let sum = num1 + num2
console.log(sum)
// 函数式
function add (n1, n2) {
return n1 + n2
}
let sum = add(1, 2)
console.log(sum)
3.函数是一等公民
- 函数可以存储在变量中
- 函数可以作为参数
- 函数可以作为返回值
// 1.函数作为变量中**
let fn = function() {
console.log('Hello')
}
let obj = {
fn: views.fn
}
// 2.函数作为参数**
let arr = [1, 2, 3, 4, 5]
// 案例 1
function forEach(arr, fn) {
for (let i = 0; i < arr.length; i++) {
fn(arr[i])
}
}
forEach(arr, function(item) {
console.log(item) // 1, 2, 3, 4, 5
})
// 案例 2
function filter(arr, fn) {
let result = []
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i])) result.push(arr[i])
}
return result
}
let results = filter(arr, (item) => {
return item % 2 === 0
})
console.log(results) // [2, 4]
// 3.函数作为返回值**
function once(fn) {
let done = false
return function() {
if(!done) {
done = true
return fn.apply(this, arguments)
}
}
}
let run = once(() => {
console.log('只执行一次')
})
run()
run()
run()
4.高阶函数的意义
- 代码简洁,灵活
- 可以帮我们屏蔽实现的细节
5.常用的高阶函数
- forEach
- map
- filter
- every
- some
- …
6.闭包
- 函数嵌套函数,内部函数可以访问外部函数的参数和变量
- 闭包可以延长外部函数内部变量作用范围
- 内部函数未被调用时会内存不会被释放 ,从而产生垃圾
function checkAge(min) {
return function(age) {
return min >= age
}
}
7.纯函数
-
相同的输入始终得到相同的输出
-
优势:
1.值可以被缓存
2.让测试更方便(如:单元测试断言函数的结果)
3.并行处理 在多线程的环境下并行操作共享的数据(es6 (web worker)可以开启多线程) -
副作用:
如果函数依赖外部的状态,无法保证输出相同let mini = 18 function (age) { return age >= mini } age(20) => true let mini = 21 age(20) => false
// 纯函数 / 不纯函数
// 纯函数
let array = [1, 2, 3, 4, 5]
array.slice(0, 3) ⇒ [1, 2, 3]
array.slice(0, 3) ⇒ [1, 2, 3]
array.slice(0, 3) ⇒ [1, 2, 3]
// 不纯的函数
array.splice(0, 3) ⇒ [1, 2, 3]
array.splice(0, 3) ⇒ [4, 5, ]
array.splice(0, 3) ⇒ []
// 纯函数
function getSum(n1, n2) {
return n1 + n2
}
getSum(1, 2) => 3
getSum(1, 2) => 3
getSum(1, 2) => 3
getSum(1, 2) => 3
8.*函数柯里化
- 当一个函数是多个参数只接收部分参数,并返回一个新的函数,来接收剩余参数 (把多元函数转换为一元函数)
- 可以把参数缓存起来
// 演示
// function checkAge(age) { // 硬编码
// let min = 18
// return age >= min
// }
// 普通的纯函数
// function checkAge(min, age) {
// return age >= min
// }
// console.log(checkAge(18, 20))
// console.log(checkAge(18, 24))
// console.log(checkAge(22, 24))
// 函数柯里化
function checkAge(min) {
return function(age) {
return age >= min
}
}
// es6 箭头函数
let checkAge = min => (age => age >= min)
let checkAge18 = checkAge(18)
let checkAge20 = checkAge(20)
checkAge18(20)
checkAge20(22)
// lodash 柯里化原理
function getSum(a, b, c) {
return a + b + c
}
function curry(func) {
return function curryFn(...args) {
// 判断实参和形参的个数
// 实参 < 形参
if (args.length < func.length) {
return function() {
return curryFn(...args.concat(Array.from(arguments)))
}
}
// 实际参数大于 等于形参
return func(...args)
}
}
curry(getSum)(1, 2, 3) // 6
curry(getSum)(1)(2, 3) // 6
curry(getSum)(1)(2)(3) // 6
9.函数组合(函数组合默认从右到左执行)
- 如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程合并成一个函数
- 函数组合可以让我们把细粒度的函数重新组合新的函数
function compose(fn1, fn2) {
return function(value) {
return fn1(fn2(value))
}
}
// 获取数组最后一个元素
function reverse(array) {
return array.reverse()
}
function first(array) {
return array[0]
}
const last = compose(first, reverse)
last([1, 2, 3, 4]) => 4