函数式编程基础概念

397 阅读5分钟

一、编程范式:

  • 面向对象程序设计(Object Oriented Programming):通过封装变化使代码更易理解
  • 函数式编程(Functional Programming):通过最小变化 使代码更易理解
    • 函数响应式编程(RP:使用异步数据流的函数式编程)
      • 有助于【数据流的处理】和【变化的传递】
  • 其他...

1. 函数式编程

1.1 定义:

强调以函数使用为主的软件开发风格。
从宏观上讲,函数式编程其实就是分解为子任务和组合子任务
函数式编程模块化的概念与单一原则息息相关

函数能组合的条件是:参数数目和类型必须相同 f*g = f(g(x)),调用顺序是翻转的

1.2 目标:

  • 使用【函数来抽象】作用在【数据之上】的【控制流与操作】,
  • 从而【消除副作用】并【减少对状态的改变】

1.3 特性:

  • 声明式编程
  • 透明引用
  • 不可变性
  • 纯函数

1.4 好处:

  • 任务分解为更小的短函数
  • 流式调用链
  • 通过响应式降低事件驱动代码的复杂性

1.5 异步响应式编程:

  • 问题:异步回调会打破线性代码流
  • 解决方案:响应式编程
  • 好处:
    • 提高代码的抽象级别
    • 降低代码复杂度
    • 充分利用函数式编程中【函数链】和【组合】的优势
  • 原理:
    • 观察者订阅数据流,开发者通过组合和链式处理数据

1.6 函数式编程和面向对象的区别:

区别函数式面向对象
组合单元函数对象(类)
编程风格声明式命令式
数据和行为独立 && 松耦合的纯函数与方法紧耦合的类
状态管理将对象视为不可变的值主张通过实例方法改变对象
程序流控制函数与递归循环与条件
线程安全可并发编程难以实现
封装性因一切不可变,没必要需要保护数据的完整性
着重点在于操作如何执行数据和数据之间的关系
预测性等式正确结果不可预测,可能不一致

1.7 为什么使用函数式编程?

随着应用程序功能越来越多,业务越来越复杂,代码会变的【笨拙而难以维护】。 将长函数分离成多个具有单一职责的短函数,尽可量的消除副作用。 严重依赖外部变量会形成一种共享的可变全局数据网,难以追踪和调试。 从而提高代码质量、增强开发技能、模块化更高效。

二、其他定义:

1. 副作用:

  • 改变全局变量
  • 改变函数参数的原始值
  • 处理用户输入
  • 抛出一个异常,除非他又被当前函数捕获
  • 屏幕打印或记录日志
  • 查看html文档,浏览器的cookie, 访问数据库

2. 纯函数:

不纯的函数结果不可预见,纯函数特性:

  • 仅取决于提供的输入,而不依赖于任何【在函数求值期间】或【调用间隔时】可能变化的【隐藏和外部状态】
  • 不会造成【超出作用域】的变化,如修改全局变量或引用对象等

2.1 纯函数的一个特质 - 引用透明:

引用透明又称”等式正确性“,最好确保一个函数有相同的返回值,他可以使得函数的结果的一致性和可预测性。因此, 如果一个函数对于相同的输入始终产生相同的结果,那么就说他是引用透明的

3. 不可变数据:

创建后不能更改的数据

4. 声明式编程:

  • 声明式代码风格提供了程序需要执行的那些高阶步骤的一个清晰视图,增强了【代码可读性】

5. 惰性计算

函数链是惰性计算, 就是需要的时候才执行,有利于性能。

6. 值对象

JS可以动态创建属性,但是也会随时被更改,是安全方面做的最差的语言。

传统意义上,字符串和数字这种原始类型本身是不可以变的,但是引用原始类型的变量状态可以被更改。 因此,提供或模拟对数据的不可变引用,才能使得自定义的对象具有近似不可变的行为。

ES6提供了const关键字表示值一旦定义不能被改变。

但是对象怎么办呢,所以就需要封装这个防止篡改的错略。

值对象:指其相等性不依赖于【标识或引用】,只基于其值,一旦声明,状态可能不会再改变。

  • Object.freeze : 浅冻结

7. 设计遵守的原则:

  • 可扩展性
  • 可复用性
  • 可测性
  • 易模块化
  • 易推理性

8. Lenses函数式引用:

是函数式程序设计中用于访问和不可改变地操纵数据状态类型属性的解决方案

本质上讲,Lensex与写时复制的策略类似,它采用一个合理管理和赋值状态的内部存储组件。

工具库Ramada.js已经实现了。

三、 Javascript语言:

  • 编程范式的宿主语言
  • 拥有【很多共享状态】的动态语言
  • 面向对象和函数式编程为一体的混合语言
  • 其实并不具备典型的继承关系,其实是使用的原型链机制

3.1 Javascript 函数:

JS函数具有值得行为

2个重要特性: 一等的和高阶的

  • 高阶函数:接受其他函数为参数返回其他函数

四、函数式编程的一些简单例子:

  1. 对象作为参数消除this的使用,消除副作用

原因:使用this的缺点是他给予了【超出方法作用域】的【实力层级】级别的【数据访问能力】,从而导致可能的副作用。
使用函数式编程,对象数据解耦,更具有重用性和维护性。

const fullgame = (person)=>{
  return person.firstName
}
  1. 闭包的实际应用:
  • 模拟私有变量
  • 异步服务端调用
  • 创建人工块作用域变量