函数式编程

 

函数式编程(简称FP):

是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是λ演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)

可以理解为,以函数作为主要载体的编程方式,用函数去拆解、抽象一般的表达式 

  • 特性

  1. 函数是一等公民。:函数可以跟其他变量一样,可以作为其他函数的输入输出。

  2. 纯函数:一个函数的输出不受外部环境影响,同时也不影响外部环境时

  3. 引用透明 :同样的输入,必定是同样的输出。函数内部不依赖外部状态,如一些全局变量。

  4. 惰性计算 :一个表达式绑定的变量,不是声明的时候就计算出来,而是真正用到它的时候才去计算

  • 常见的函数式编程模型 

  1. 闭包

    创造条件是: 

  • 存在内、外两层函数
  • 内层函数对外层函数的局部变量进行了引用
    // 简单的缓存工具  
    // 匿名函数创造了一个闭包  
    const cache = (function () {
        const store = {};

        return {
            get(key) {
                return store[key];
            },
            set(key, val) {
                store[key] = val;
            }
        }
    }());

    cache.set('a', 1);
    cache.get('a');  // 1 

 

2.柯里化

给定一个函数的部分参数,生成一个接受其他参数的新函数

简单来讲就是部分应用, 也就是说 只传递函数的一部分参数来调用它,让它返回一个函数去处理剩下的参数

// 柯里化之前
function add(x, y) {
    return x + y;
}
add(1, 2) // 3
// 柯里化之后
function addX(y) {
    return function (x) {
        return x + y;
    };
}
addX(2)(1) // 3

传入的参数个数是不固定的

function add(){
    var args = [].slice.call(arguments);
    var fn = function(){
        var newArgs = args.concat([].slice.call(arguments));
        return add.apply(null,newArgs);
    } 
    fn.toString = function(){
        return args.reduce(function(a, b) {
            return a + b;
        })
    }
    return fn ;
}

add(1)(2,3) //6
add(1)(2)(3)(4)(5) //15

这里就需要使用函数的toString来完成。 
当我们返回函数的时候,会调用函数的toString来完成隐式转换。

 

3.组合

组合,顾名思义,也就是把多个函数组合起来变成一个函数。为了解决函数嵌套过深,包菜代码:h(g(f(x))),我们需要用到“函数组合”,让多个函数像拼积木一样。

const compose = (fn1, fn2) => args => fn1(fn2(args));

const toUpperCase = value => value.toUpperCase();
const addSuffix = value => `${value} is good!`;

const format = compose(toUpperCase, addSuffix);
format('apple'); // "APPLE IS GOOD!"

//fn2 先执行,然后将返回值作为 fn1 的参数,所以 compose 里面的方法是从右向左执行的

 

4.高阶函数 

 接受或者返回一个函数的函数称为高阶函数

当情况变得更加复杂时,表达式的写法会遇到几个问题: 

  • 表意不明显,逐渐变得难以维护
  • 复用性差,会产生更多的代码量
  • 会产生很多中间变量

在 JavaScript 中见到许多原生的高阶函数,例如 Array.map , Array.reduce , Array.filter

例如:

map 作为一个高阶函数,他接受一个函数参数作为映射的逻辑

// 数组中每一项加一,组成一个新数组  
// 一般写法  
const arr = [1, 2, 3];
const rs = [];
for (const n of arr) {
    rs.push(++n);
}
console.log(rs)

// map改写  
const arr = [1, 2, 3];
const rs = arr.map(n => ++n); 

 

 

  • 声明式与命令式代码

        //命令式
        let companies = [{name:"ellen",age:11},{name:"ant",age:23}];
        let names = [];
        for (var i = 0; i < companies.length; i++) {
            names.push(companies[i].name)
        }
        //声明式
        let names = companies.map(c => c.name);
    ​​
  • 优点

  1. 可复用性更高
  2. 可维护性更好
  3. 作用域局限,副作用少
  4.  更方便的代码管理

函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试和除错,以及模块化组合。

  • 总结

面向对象对数据进行抽象,将行为以对象方法的方式封装到数据实体内部,从而降低系统的耦合度。而函数式编程,选择对过程进行抽象,将数据以输入输出流的方式封装进过程内部,从而也降低系统的耦合度。函数对于外部状态的依赖是造成系统复杂性大大提高的主要原因,函数式编程能拓展我们的思维,不局限在过程式的编程代码。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值