Javascript函数式编程

99 阅读2分钟

什么是函数式编程?

函数式编程技术主要基于数学函数和它的思想所诞生的一种编程范式。 本质上是一种数学运算:f(x)=y;

个人理解: 在函数式编程中,函数就是一个流水线,传递进去的数据(参数)就像是要加工的产品,我们可以通过用不同的加工设备加工出不一样的产品,但是这条流水线始终不会出现其他产线的任务产品。如:rxjs里面pipe管道概念一样;

纯函数是什么?

  • 函数内部不会依赖和影响外部的任何变量
  • 相同的输入,永远会得到相同的输出
  • 可缓存,可测试,可并发
  • 引用透明,不可变数据

结果可以被缓存,因为相同的输入总会获得相同的输出

更加容易被测试,因为它们唯一的职责就是根据输入计算输出

//普遍函数----不可并行
let global = 'globalVar';
let function1 = (input) => {
    global = "somethingElse" 
} 
let function2 = (global) => { 
    if(global === "something"){ // 业务逻辑 } 
}
//纯函数
let function1=(input,global)=>{
    global = "somethingElse" 
}
let function2 = (global) => { 
    if(global === "something"){ // 业务逻辑 } 
}

声明式编程

函数式编程就是属于声明式编程范式。

// 命令式方式: 强调做什么 
let arr = [0, 1, 2, 3]; 
for(let i = 0; i < arr.length; i++) { 
    array[i] = Math.pow(array[i], 2) 
} // [0, 1, 4, 9] 

// 声明式方式: 强调如何做, 通过将逻辑封装抽离出来, 达到抽象的目的 
[0, 1, 2, 3].map(num => Math.pow(num, 2)) // [0, 1, 4, 9]

函数的几种用法

  • 柯里化函数
  • 偏函数
  • 管道&组合

柯里化函数

将一个多元函数变成多个嵌套的一元函数;

const curry=(fn,...args)=>{
    const len=fn.length;
    return function(...inner){
        inner=args.concat(inner);
        if(inner.length<len){
            return curry.call(this,fn,inner)
        }else{
            return fn.apply(this,inner)
        }
    }
}
const add=curry((a,b,c)=>a+b+c);
add(1)(2,3);add(3)(2)(1);

偏函数应用

固定函数的一个或者多个参数,返回一个新的函数,这个函数接受剩余的参数;

function partial(fn,...presetArgs){
    return function(...args){
        return fn(...args,...presetArgs)
    }
}

函数组合&管道

函数组合的思想就是把小函数组合成一个大函数,仅当函数接受一个参数时,才能将函数组合,因此需要柯里化函数

const compose=function(...fn){
    return (value)=>reduce(fn.reverse(),(acc,cur)=>cur(acc),value);
}

函数式组合是满足结合律的:

compose(f,compose(g,h))===compose(compose(f,g),h)

管道:参数从左到右pipe

组合:参数从右到左compose

什么是函子?

函子是一个普通对象或类,它实现了map函数,在遍历每个对象的时候生成一个新对象,函子是一个持有值的容器,是一个实现了map契约的对象; MayBe函子

const MayBe=function(val){ 
    this.value=val; 
}
MayBe.of=function(val){ 
    return new MayBe(val) 
};
MayBe.prototype.isNothing=function(){
    return (this.value===null || this.value===undefined)
}
MayBe.prototype.map=function(fn){
    return this.isNothing()?Maybe.of(null):MayBe.of(fn(this.value));
}