第四章 高阶函数

作者: 549b968de8fa | 来源:发表于2017-03-26 14:49 被阅读38次

    4.1 以其它函数为参数的函数

    还记得我们第二章讲到的 filter() 函数吗?那就是一个高阶函数。

    假如现在,我们想要一个函数,用于返回数组中最大的数,我们应该怎么做呢?

    const max = value => Math.max(...value);
    
    const find = (array, math) => {
      return math(array);
    };
    
    find([1, 2, 3, 4], max);  // 4
    

    你也许会奇怪,为什么我这里要定义一个 find 函数呢?还记得我们第一章所说的吗?函数式编程最重要的是抽象和函数组合。

    假如我们现在又有需求,需要找到最小值呢?需要将这些值相加呢?需要将值相乘呢?那么我们只需定义其它函数就可以了,而对 find 函数没有任何“副作用”,这也是函数式编程中很重要的思想,函数不能有副作用,输入什么值就会输出什么值,比如 1 + 1 = 2 而不是以字符串表示的 '2'。

    const min = value => Math.min(...value);
    
    const multiply = (a, b) => a + b;
    
    const reduce = array => array.reduce(multiply, 0);
    

    以上,我们又定义了几个函数,发现了吗,这些函数都是单独独立的,与 find 函数毫无关系。

    当我们需要使用的时候,进行组合就可以了:

    find([1, 2, 3], min);  // 1
    find([1, 2, 3], reduce);  // 6
    

    不知道你学会了吗?我们要学习思想,思想是前进的唯一动力,仿写和抄袭代码会让你变得更熟练,但不会让你变成大师。

    这也是为什么大师会悟道,而高手只会学习武功秘籍。

    4.2 返回其它函数的函数

    高级函数的参数是用于“配置”返回的函数的行为的。

    比如下面的例子:

    const add = function (x) {
      return function (y) {
        return x + y;
      }
    };
    
    const add100 = add(100);
    
    const add50 = add100(50);
    
    console.log(add50);  // 150
    

    上面的函数,我们可以叫它为 “柯里化(currying)” 。但是这里先不涉及它的概念。

    我么可以看到,第一次我们传入的 x 的值为 100,将其作为一个值再传给了 add50 函数。也就是说,我们未来不论传入任何值,add100 的值都是 100,还记得我说的吗,函数是不能有副作用的。我们再用平常的写法写一遍:

    function add(a, b) {
      return a + b;
    }
    add(100, 50);  // 150
    

    没有什么问题,不用担心我会在这里挖什么坑。

    相信你会认为上面的函数式写法更不方便对吧。那么,我们就来看看到底它有什么好处。

    假设,你要实现生成一个随机字符串的方法:

    // 这里的 36 表示 36 进制,支持 2 ~ 36 进制
    const randomStr = length => Math.random().toString(36).substring(2, length);
    
    randomStr(10);  // y650pn90
    

    假如现在我改需求了,我要生成有固定的前缀的字符串怎么办,好吧,我改...

    const prefixStr = (prefix, length = 10) => {
      return [prefix, Math.random().toString(36).substring(2, length)].join('');
    };
    
    prefixStr('Hello-', 8);  // Hello-pga6y2
    

    没问题,但是。。。你没有发现,这里好像是不是重复了呀!这不符合我们对函数解耦的观念,改改改!

    function prefixRandomStr(length) {
      return function (prefix) {
        return [prefix, Math.random().toString(36).substring(2, length)].join('');
      }
    }
    
    const randomString = prefixRandomStr(10);
    randomString();  // uf65je7i
    
    const prefix = randomString('I-love-');
    prefix;  // I-love-lw4f5af6
    

    这样,我们就实现了函数的解耦和分离功能。

    你会发现,我们上面的函数返回的结果是不一样的对吧,不对那就对了!这样,当我们需要前面的函数,就可以只运行前面的函数,而需要加上前缀的时候,我们再调用高阶函数中的另一个函数就可以了。

    这里再穿插一个函数式编程中的概念 —— 一个拥有可变状态的函数具有潜在的危险,我们应该尽量避免创建和使用它。

    总结

    本节我们讲了函数式编程中非常重要的概念之一 —— 高阶函数。

    我们不仅讲了怎么使用它,更重要的是要学会为什么要使用它,以及在什么情况下,我们最好使用高阶函数。

    相关文章

      网友评论

        本文标题:第四章 高阶函数

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