架构整洁之道-03编程范式-函数式编程

这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

函数式编程

架构设计另一个编程范式—函数式编程,其主要关心数据到数据之间的映射关系,即将计算过程抽象描述成一种表达式求值。先看下以下实现数组转换成数组对象的函数代码:

// 实现数组转换数组对象
function AryToObjectAry() {
  const ary = ["jasen-yang", "tom-han", "marry-han", "lucy-any"];
  const newObj = [];
​
  ary.forEach((value) => {
    let names = value.split("-");
    let newNames = [];
    names.forEach((name) => {
      const temp = name[0].toUpperCase() + name.slice(1);
      newNames.push(temp);
    });
    newObj.push({ name: newNames.join(" ") });
  });
  console.log(newObj);
  return newObj;
}
​
(()=>{
    AryToObjectAry()
})();
​
// 输出结果
[
  { name: 'Jasen Yang' },
  { name: 'Tom Han' },
  { name: 'Marry Han' },
  { name: 'Lucy Any' }
]
复制代码

定义变量,循环数组,把值开头大写,每个函数各司其职,按一定的步骤,从函数输入到输出结果。从代码上阅读可以很清楚知道在做什么,但是一但出问题就很难定位,其中掺杂了大些逻辑和变量。

如果每个过程都是一个函数,会怎么样?看下以下伪代码:

​
function convertAry() {
  const ary = ["jasen-yang", "tom-han", "marry-han", "lucy-any"];
​
  const getNames = (value) => {
    return value.split("-");
  };
  const toUpper = (value) => {
    return value[0].toUpperCase() + value.slice(1);
  };
  const convertName = (newObj,value) => {
    return newObj.push({ name: value });
  };
​
  const newObj = [];
  ary.forEach((value)=>{
    const newName = compose(getNames(value),toUpper);
    const result = compose(newObj,convertName(newName));
  });
  return newObj;
}
复制代码

看整个编程思路,可以清晰看出,函数式编程,重点是函数而不是过程,通过函数的组合变换去解决问题。每个函数可以看出在做什么,一目了然,函数让代码更加语义化,可读性更高。

函数式编程,重点是在构建关系,通过构建一条高效的流水线,一次解决所有的问题,而不是关注各个函数之间的数据。

函数式编程特点

函数式一等公民

在函数式编程中,变量是不能被修改的,所有的变量只能被赋值一次,所有的值全都靠传参来解决的。函数作为一等公民,可以在任何地方定义,可以作为参数和返回值,可以对函数进行组合。

无状态和数据不可变

函数式编程的核心

  • 数据不可变,若修改一个对象,应建一个新对象而不是修改已有的对象
  • 无状态,对于一个函数,无论何时运行,在给定的相同输入都能输出相同结果,完全不依赖外部状态的变化

惰性执行

函数只在需要的适合执行,不产生无意义的中间变量。比如,在处理过程中都在写函数,而只有在最后才去产生实际的结果。

参考资料

\