javascript中的函数式编程

作者: 子龙0322 | 来源:发表于2018-11-18 02:22 被阅读66次

    随着 React 的大火,也让函数式编程越来越受到前端er的关注(React大量借鉴了函数式编程的思想,如一个组件基本就是一个「纯函数」)。

    但JS毕竟不同于Lisp或Haskell,函数式编程只是JS具有的一项能力。
    在此,将我认为函数式编程对JS开发很有价值的思想梳理一下:

    1. 纯函数
      即无副作用的函数:
      1)不会改变函数实参的值(immutate)。如数组的slice方法便不会改变原数组的值(immutate), 而数组的push方法便会改变原数组的值(mutate)。
      2)不会调用外部作用域的变量。
      其意义:使得函数与外部解耦,函数的使用更加安全。

    2. 柯里化
      其思想为,任何一个多参的“基础函数”,可以通过闭包等技术将该函数的前几个参数赋值,从而将该函数“赋能”为“定制函数”。

    function add(a, b) {
      return a + b;
    }
    // add(2, 5); // 7
    
    // 将其改写为 add(2)(5) // 7
    function add(a) {
      return b => a + b;
    }
    add(2)(5); // 7
    // add(2)(5)等同于
    const add2 = add(2); // add2 便是柯里化后的函数
    add2(5); 
    

    其意义:大量的“定制函数”,都可通过“基础函数”的柯里化得到,能极大简化代码。
    注:函数的柯里化可通过 Lodash 的 _.curry 轻易实现。

    1. compose
      其思想为将数据依次经过几个函数处理(函数的嵌套),最终输出结果数据。
      注:由于 compose 的实现与使用较麻烦,Lodash 的 _.flow 提供了 compose 的功能,且可读性更强,下例以 _.flow + _.curry 实现 compose 的demo:
    // 求出 data 中, 年龄在20岁以上,体重最小者:
    import _ from 'lodash';
    const data = [
      {name: 'a', age: 37, weight: 72},
      {name: 'b', age: 17, weight: 64},
      {name: 'c', age: 24, weight: 89},
      {name: 'd', age: 66, weight: 83},
      {name: 'e', age: 47, weight: 105},
      {name: 'f', age: 18, weight: 61}
    ];
    
    function filterBy(predicate, data) {
      return data.filter(predicate);
    }
    
    function sortBy(field, data) {
      return data.sort((a, b) => a[field] - b[field]);
    }
    function head(data) {
      return data[0];
    }
    
    _.flow([
      _.curry(filterBy)(d => d.age > 20), // 筛选 20 岁以上的对象
      _.curry(sortBy)('weight'), // 以 weight 进行排序
      head // 获得数组第一个元素
    ])(data); // {name: "a", age: 37, weight: 72}
    

    另外, lodash 可作函数式编程,以上代码,改为 lodash 代码:

    // 求出 data 中, 年龄在20岁以上,体重最小者:
    import _ from 'lodash';
    import fp from 'lodash/fp';
    const data = [
      {name: 'a', age: 37, weight: 72},
      {name: 'b', age: 17, weight: 64},
      {name: 'c', age: 24, weight: 89},
      {name: 'd', age: 66, weight: 83},
      {name: 'e', age: 47, weight: 105},
      {name: 'f', age: 18, weight: 61}
    ];
    
    _.flow([
      fp.filter(d => d.age > 20),
      fp.sortBy('weight'),
      _.head
    ])(data) // {name: "a", age: 37, weight: 72}
    

    其意义:从 .flow 的每一步中,以函数名便知该步的意图,这便是函数式编程的一大好处——声明式(Declarative)的编程方式。


    有了函数式编程的思想,则在开发时,最小的代码单位是“基础函数”,通过 柯里化 + compose(
    .flow) 使得开发就像“搭积木”一样,通过函数的各种组装,便能组织成完整代码。


    综上,开发中,仅使用以上三点,就能带来的好处有:
    1,可读性强:声明式(Declarative)使得代码即使没有注释也有很高的可读性(这也是 React 的一大卖点)。
    2,代码量少:项目越大,越节省代码量(大量的函数被复用)。
    3,代码稳定可靠:纯函数的功劳。
    4,容易维护性:符合「单一职能原则」,使得代码的维护与迭代更加容易。

    相关文章

      网友评论

        本文标题:javascript中的函数式编程

        本文链接:https://www.haomeiwen.com/subject/mujwfqtx.html