学习函数式编程需要非常熟悉以下概念

  • 函数是一等公民
  • 定义最少的无关临时变量
  • 灵活使用函数作为函数的值

所以什么是函数式编程

这里我使用一个比较好理解的方式来说

函数式编程就是规范的使用函数,组合一些小函数来构建一个新函数;函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式。

函数式编程在前端开发中最直观的体验就是

  1. 流程变量赋值后就不去修改,虽然算不上声明式编程,但利于人脑理解。
  2. 处理容器数据结构时多用高阶函数,少用for,while和break,虽然不一定能算上函数式,但利于产生更短小易理解的代码

说人话就是尽可能不要定义let var 所有变量都是const ,不允许修改变量,子函数修改变量是很多bug的源泉

JS数组原生方法中的函数式用法

1、filter

接收一个函数创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素

案例

var animals = [
    {name:'apply0',species:'rabbit0'},
    {name:'apply1',species:'rabbit1'},
    {name:'apply2',species:'dogs'},
    {name:'apply3',species:'rabbit3'},
    {name:'apply4',species:'rabbit4'},
    {name:'apply5',species:'rabbit5'}
]
//函数式编程
var dogs = animals.filter((x)=>x.species === 'dogs')

// 传统方式
var dogs = []
for(var i = 0; i<animals.length;i++){
    if(animals[i].species === 'dogs'){
        dogs.push(animals[i])
    }
}

console.log(dogs)

当可能需要多个场合判断 species === 'dogs' 时,可以将其提取出为一个函数,此时的使用如下

var findSpecies = (x)=>{return x.species === 'dogs'}
var dogs = animals.filter(findSpecies)

2、map

接收一个函数,返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值

var animals = [
    {name:'apply0',species:'rabbit0',code:'1120'},
    {name:'apply1',species:'rabbit1',code:'1121'},
    {name:'apply2',species:'dogs',code:'1122'},
    {name:'apply3',species:'rabbit3',code:'1123'},
    {name:'apply4',species:'rabbit4',code:'1125'},
    {name:'apply5',species:'rabbit5',code:'1124'}
]
// 函数式编程
var names = animals.map((x)=>x.name)
// 传统方式
var names = []
for(var i = 0; i<animals.length;i++){
    names.push(animals[i].name)
}
 获取code拼接值-- 常用  输出 1120,1121,1122,1123,1125,1124
var codes = animals.map((x)=>x.code).toString()

3、 reduce

接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值

array.reduce(function(total, currentValue, currentIndex, arr), initialValue) f(初始值, 或者计算结束后的返回值;当前元素;当前元素的索引;当前元素所属的数组对象),传递给函数的初始值

任何现有方法无法满足数组操作要求都可以转化使用reduce来满足需求

// 实现基本求和
var orders = [
  { amount: 250 },
  { amount: 34 },
  { amount: 243 },
  { amount: 76 },
  { amount: 65 },
  { amount: 45 },
  { amount: 44 },
];
// reduce
var totalAmount = orders.reduce((sum, order) => sum + order.amount, 0);
// 传统方式
var totalAmount = 0;
for (let i = 0; i < orders.length; i++) {
  totalAmount += orders[i].amount;
}

console.log(totalAmount);

完成一个data.txt文件数据的整理

mark johnwaff 80 32
mark ssdswaff830 324
nik Smaswaff 80 3
nik grff 650 34
shem shiji 90 4
var fs = require("fs");
var output = fs
  .readFileSync("data.txt", "utf8")
  .trim()
  .split("\n")
  .map((line) => line.split(" "))
  .reduce((customers, line) => {
    customers[line[0]] = customers[line[0]] || [];
    customers[line[0]].push({
      name: line[1],
      price: line[2],
      quantity: line[3],
    });
    return customers;
  }, {});
console.log(JSON.stringify(output, null, 2));

输出

{
  "mark johnwaff 80 32": [
    {}
  ],
  "mark ssdswaff830 324": [
    {}
  ],
  "nik Smaswaff 80 3": [
    {}
  ],
  "nik grff 650 34": [
    {}
  ],
  "shem shiji 90 4": [
    {}
  ]
}
shensai@192 Function-code % node array.js
{
  "mark": [
    {
      "name": "johnwaff",
      "price": "80",
      "quantity": "32"
    },
    {
      "name": "ssdswaff830",
      "price": "324"
    }
  ],
  "nik": [
    {
      "name": "Smaswaff",
      "price": "80",
      "quantity": "3"
    },
    {
      "name": "grff",
      "price": "650",
      "quantity": "34"
    }
  ],
  "shem": [
    {
      "name": "shiji",
      "price": "90",
      "quantity": "4"
    }
  ]
}

ES自带的高阶函数API

1、Array every()

检测数组所有元素是否全部都符合指定条件

const ages = [1,2,3,2,3,24,23,4,23,43,5,43];
const isMax = (agesArr,min) => {
  return agesArr.every((e) => e > min);
};
console.log(isMax(ages,0));

2、Array some()

检测数组是否有满足指定条件的值

const ages = [1,2,3,2,3,24,23,4,23,43,5,43];
const isMax = (agesArr,min) => {
  return agesArr.some((e) => e > min);
};
console.log(isMax(ages,));

3、Array sort()

对数组进行排序

const ages = [1,2,3,2,3,24,23,4,23,43,5,43];
const sortArr = (agesArr) => {
  return agesArr.sort((a,b) => a-b);
};
console.log(sortArr(ages) );

总结

高效函数式编程就是把多个独立函数组合在一起使用,类似的链式调用就是常见手段