函数式编程总结(一)

187 阅读2分钟

「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。

为什么要学习函数式编程

  • react中用到了函数式编程
  • Vue3中也开始使用函数式编程
  • 函数式编程可以抛弃this
  • 打包过程中可以更好地利用tree shaking过滤无用代码
  • 方便测试和并行处理
  • 很多库可以帮助我们进行函数式开发,例如lodash、underscore、ramda等

什么是函数式编程

函数式编程就是利用纯函数来实现细粒度的函数,再通过函数组合把这些细粒度的函数组合成功能更强大的函数。

函数式编程是对运算过程进行抽象,是一种映射关系(数学中的函数),来描述数据(函数)之间的映射。 函数式编程中的函数一定要有输入和输出,而且根据相同的输入要有相同的输出。

lodash是函数式编程库。

高阶函数

函数是一等公民,体现在:

(1)函数可以存储在对象中

(2)函数可以作为参数

(3)函数可以作为返回值

在JavaScript中函数就是一个普通对象,可以通过new Function()来创建一个函数。

高阶函数定义:

  • 可以把函数作为参数传递给另一个函数
  • 可以把函数作为另一个函数的返回值

常用的高阶函数有forEach、map、filter、every、some、find等。

// 函数作为参数
function forEach(array, fn) {
  for (let i = 0; i < array.length; i++) {
    fn(array[i])
  }
}

const arr = [1, 3, 4, 5, 6]
forEach(arr, function (item) {
  console.log(item);
})
// 函数作为返回值
function makeFn() {
  let msg = 'hello world'
  return function() {
    console.log(msg);
  }
}

makeFn()()

闭包

函数和其周围状态(词法环境)的引用捆绑在一起形成闭包。可以在另一个作用域中调用一个函数并访问到该函数的作用域中的成员。

闭包的本质:函数在执行的时候会放在一个执行栈上,当函数执行完毕后会从执行栈上移除。但是堆上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问外部函数的成员。

    function makePower (power) {
      return function (number) {
        return Math.pow(number, power)
      }
    }

    let power2 = makePower(2)
    let power3 = makePower(3)

    console.log(power2(4));
    console.log(power2(5));
    console.log(power3(4));

纯函数

纯函数:相同的输入永远会得到相同的输出,并且没有任何可观察的副作用

函数式编程中的函数就是纯函数。函数式编程不会保留计算中间的结果,所以变量是不可变的(无状态的)。

lodash是一个纯函数的功能库,提供了对数组、数组、对象、字符串、函数等操作的一些方法。

数组中的slice不会改变原数组,它是一个纯函数。 数组中的splice会改变原数组,它不是一个纯函数。

let array = [1, 2, 3, 4, 5]
// 纯函数
console.log(array.slice(0,3));
console.log(array.slice(0,3));
console.log(array.slice(0,3)); 

// 不纯的函数
console.log(array.splice(0,3));
console.log(array.splice(0,3));
console.log(array.splice(0,3));

副作用会让一个函数变为不纯的。纯函数,相同的输入会有相同的输出,但是如果函数依赖于外部状态就无法保证输出相同,就会带来副作用。

let mini = 18
function checkAge (age) {
    return age >= mini
}

柯里化

柯里化接收一部分参数,返回一个新函数接收剩余参数,返回结果。

function checkAge (min) {
  return function (age) {
    return age >= min
  }
}

let checkAge18 = checkAge(18)
let checkAge20 = checkAge(20)

console.log(checkAge18(20));
console.log(checkAge18(24));
  • 柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数
  • 对函数参数进行缓存
  • 让函数变得更灵活,让函数粒度更小
  • 可以把多元函数转换成一元函数,可以组合使用函数产生强大功能