函数式编程

什么是函数式编程?

主要的编程范式有三种:命令式编程、声明式编程和函数式编程

函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导的运算,而非设计一个复杂的执行过程。简单的来说,就是把过程逻辑变成函数,定义好输入参数,只关心它的输出结果。

优点:

  • 更好的状态管理:因为它的宗旨是无状态,或者更少的状态,能最大化的减少这些未知、优化代码、减少出错情况
  • 更简单的复用:固定输入 -> 固定输出,没有其他外部变量影响,并且无副作用。这样代码复用时,完全不需要考虑它的内部实现和外部影响
  • 更加优雅的组合:一个函数也可能有由多个小函数组成的。更强的复用性,带来更强大的组合性
  • 减少代码量,提高维护性

缺点:

  • 性能:函数式编程相对于指令式编程,性能决定是一个短板,应该它往往会对一个方法进行过度包装,从而产生上下文切换的性能开销

  • 资源占用:在 JS 中为了实现对象的状态的不可变,往往会创建新的对象。因此,它对垃圾回收所产生的压力远远超过其他编程方式

  • 递归陷阱



纯函数

纯函数,无副作用的函数,是对给定的输入返回相同输出的函数,并且要求你所有的数据都是不可变的,即纯函数 = 无状态 + 数据不可变。

特点:

  • 函数内部传入的指定值,就会返回确定唯一的值
  • 不会造成超出作用域的变化,例如修改全局变量或者引用传递的参数

优势:

  • 不依赖外部环境计算,不会产生副作用,提高函数的复用性
  • 可读性更强,函数不管是否纯函数,都会有一个语义化的名称,更便于阅读
  • 可以组装成复杂任务的可能性,符合模块化概念及单一职责原则

高阶函数

以函数作为输入或者输出的函数称为高阶函数。

const forEach = function(arr,fn){
  for(let i = 0;i < arr.length; i++){
    fn(arr[i])
  }
} 

let arr = [1,2,3]
forEach(arr,(item)=>{
  console.log(item)
})




// 高阶函数存在缓存的特性,主要是利用了闭包
const once = (fn) => {
  let done = false
  return function () {
    if (!done) {
      fn.apply(this, fn)
    } else {
      console.log('该函数已经执行')
    }
    done = true
  }
}

let hello = once(()=>{
  console.log('hello')
})

hello() // hello
hello() // 该函数已经执行

柯里化

柯里化是把一个多参数函数转化成一个嵌套的一元函数过程

意义:

  • 让纯函数更纯,每次接收一个参数,松散解耦
  • 惰性执行(函数只有在需要的时候执行,即不产生无意义的中间变量)
// 二元函数
// let fn = (x,y) => x + y
// console.log(fn(1,2))

// 转成柯里化函数(二元)
// const curry = function(fn){
//   return function(x){
//     return function(y){
//       return fn(x,y)
//     }
//   }
// }
// let curryFn = curry(fn)
// console.log(curryFn(1)(2))


// 多参数柯里化
const curry = function (fn) {

  return function curriedFn(...args) {
    // 递归收集参数
    // console.log(args)
    if (args.length < fn.length) {
      return function () {
        return curriedFn(...args.concat([...arguments]))
      }
    }
    return fn(...args)
  }
}

const fn = (a, b, x, y, z) => a + b + x + y + z
const curryFn = curry(fn)
console.log(curryFn(1)(2)(3)(4)(5))

组合与管道

组合函数,目的是将多个函数组合成一个函数

意义:把很多个小函数组合起来完成更加复杂的逻辑

function afn(a) {
  return a * 2
}

function bfn(b) {
  return b * 3
}
const compose = (a, b) => c => a(b(c))
let myFn = compose(afn, bfn)
console.log(myFn(2))

// 组合函数 (从右往左执行)
const compose2 = (...fns) => val => fns.reverse().reduce((acc, fn) => fn(acc), val)
let myFn = compose2(afn, bfn)
console.log(myFn(2))


// 管道函数 (从左往右执行)
const pipe = (...fns) => val => fns.reduce((acc, fn) => fn(acc), val)
let pipeFn = pipe(afn,bfn)
console.log(pipeFn(2))

函数缓存

函数缓存,就是将函数运算过的结果进行缓存

本质上就是利用空间(缓存存储)换时间(计算过程)

应用场景:

  • 对于昂贵的函数调用,执行复杂计算的函数
  • 对于具有有限且高度重复输入范围的函数
  • 对于具有重复输入值的递归函数
  • 对于纯函数,即每次使用特定输入调用时返回相同输出的函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值