函数基础知识

  • 函数就是一个普通的对象,可储存再变量中、可作为参数也可作为函数返回值
  • 高阶函数
    • 传入一个函数,返回一个函数;封装一些代码逻辑,返回处理结果,使函数通用化
  • 闭包

    闭包概念:可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的变量,延长局部作用域变量的使用范围

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

    函数式编程基础

  • 纯函数

    1. 1. 概念:相同的输入永远会得到相同的输出,而且没有任何可观察的副作用
    2. - 什么是副作用

让一个函数变的不纯(如上例),纯函数的根据相同的输入返回相同的输出,如果函数依赖于外部的状态就无法保证输出相同,就会带来副作用。

  • 所有的外部交互都有可能带来副作用,副作用也使得方法通用性下降不适合扩展和可重用性,同时副作用会给程序中带来安全隐患给程序带来不确定性,但是副作用不可能完全禁止,尽可能控制它们在可控范围内发生。
    1. 1. 纯函数的好处:因为纯函数对相同的输入始终有相同的结果,所以可以把纯函数的结果缓存起来
    • 3.lodash
      • lodash 是一个纯函数的功能库,提供了对数组、数字、对象、字符串、函数等操作的一些方法
  • 柯里化
    • 基本概念:当一个函数有多个参数的时候先传递一部分参数调用它(这部分参数以后永远不变)然后返回一个新的函数接收剩余的参数,返回结果
    • 1.柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数
      2.这是一种对函数参数的’缓存’
      3.让函数变的更灵活,让函数的粒度更小
      4.可以把多元函数转换成一元函数,可以组合使用函数产生强大的功能
  • 组合函数

    • 概念:函数组合 (compose):如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数

      • 函数就像是数据的管道,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终
        结果
        函数组合默认是从右到左执行
      • lodash 中的组合函数
        lodash 中组合函数 flow() 或者 flowRight(),他们都可以组合多个函数
        flow() 是从左到右运行
        flowRight() 是从右到左运行,使用的更多一些
      • 示例
        1. function compose (...args) {
        2. return function (value) {
        3. return args.reverse().reduce(function (acc, fn) {
        4. return fn(acc)
        5. }, value)
        6. }
        7. }
    • 调试:在传递的函数组合中插入一个调试函数,例如log函数打印运行阶段的值

    • Point Free
      • 概念
        • 我们可以把数据处理的过程定义成与数据无关的合成运算,不需要用到代表数据的那个参
          数,只要把简单的运算步骤合成到一起,在使用这种模式之前我们需要定义一些辅助的基本运算函数。
      • 示例 ```javascript const fp = require(‘lodash/fp’) const firstLetterToUpper = fp.flowRight(join(‘. ‘),

    fp.map(fp.flowRight(fp.first, fp.toUpper)), split(‘ ‘))

    console.log(firstLetterToUpper(‘world wild web’)) ```

    Functor(函子)

  • 基本示例

    1. // 一个容器,包裹一个值
    2. class Container {
    3. // of 静态方法,可以省略 new 关键字创建对象
    4. static of (value) {
    5. return new Container(value)
    6. }
    7. constructor (value) {
    8. this._value = value
    9. }
    10. // map 方法,传入变形关系,将容器里的每一个值映射到另一个容器
    11. map (fn) {
    12. return Container.of(fn(this._value))
    13. }
    14. }
    15. // 测试
    16. Container.of(3)
    17. .map(x => x + 2)
    18. .map(x => x * x)

    s

  • 容器:包含值和值的变形关系(这个变形关系就是函数)函子:是一个特殊的容器,通过一个普通的对象来实现,该对象具有 map 方法,map 方法可以运行一个函数对值进行处理(变形关系)

    • mayBe函子
      • 添加一个方法判断传入的数据是否是null 或 undefined,对外部的空值情况做处理防止函数执行异常
    • dither 函子
      • Either 函子可以用来做异常处理,可配合try catch 使用捕获错误
  • IO函子

    • 示例

      1. const fp = require('lodash/fp')
      2. class IO {
      3. static of (value) {
      4. return new IO(function () {
      5. return value
      6. })
      7. }
      8. constructor (fn) {
      9. this._value = fn
      10. }
      11. map (fn) {
      12. return new IO(fp.flowRight(fn, this._value))
      13. }
      14. }
      15. // 调用
      16. let r = IO.of(process).map(p => p.execPath)
      17. // console.log(r)
      18. console.log(r._value())
    • IO 函子中的 _value 是一个函数,这里是把函数作为值来处理
      IO 函子可以把不纯的动作存储到 _value 中,延迟执行这个不纯的操作(惰性执行),包装当前的操作纯
      把不纯的操作交给调用者来处理

    • task 异步
      • Task 是 folktale 库中提供的方法,用来处理异步操作
      • folktale
        • folktale 一个标准的函数式编程库和 lodash、ramda 不同的是,他没有提供很多功能函数只提供了一些函数式处理的操作,例如:compose、curry 等,一些函子 Task、Either、MayBe 等
    • Pointed 函子
      • Pointed 函子是实现了 of 静态方法的函子
        of 方法是为了避免使用 new 来创建对象,更深层的含义是 of 方法用来把值放到上下文Context(把值放到容器中,使用 map 来处理值)
    • Monad 函子
      • Monad 函子是可以变扁的 Pointed 函子,IO(IO(x)),为解决函子嵌套问题