• 理解javascript中的函数组合


    理解javascript中的函数组合

    什么是函数组合

    函数组合是一种组合两个或多个函数以生成新函数的技术。这个想法是获取一个函数的输出并将其用作另一个函数的输入。

    在数学上,给定两个函数fg,它们的组合表示为f(g(x))。这里,g(x)首先计算 ,并将其结果传递给f

    const f = x => x + 2;
    const g = x => x * 3;
    
    // f、g进行组合
    const composedFunction = x => f(g(x)); // f(g(x)) = f(3x) = 3x + 2
    
    console.log(composedFunction(2)); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    简单的比喻

    让我们将函数组合与制作三明治联系起来,这是我们大多数人都熟悉的现实世界的例子。

    1. 面包切片功能:首先将面包切片。
    2. 涂抹功能:接下来,涂抹黄油、蛋黄酱或其他任何涂抹酱。
    3. 馅料功能:最后,添加馅料——生菜、番茄、奶酪等。

    制作三明治的每个步骤都可以表示为一个函数。当你组合这些函数时,你会得到一个制作三明治的组合函数。

    用 JavaScript 分解它

    让我们将三明治类比转化为 JavaScript 函数。

    // 切片
    const sliceBread = bread => `${bread} is sliced`;
    
    // 涂抹
    const spreadButter = bread => `Butter spread on ${bread}`;
    
    // 添加材料
    const addFilling = bread => `Filling added to ${bread}`;
    
    
    const makeSandwich = bread => addFilling(spreadButter(sliceBread(bread)));
    
    console.log(makeSandwich("meat")); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可重用性和可维护性

    函数组合的主要好处之一是可重用性。创建的每个功能都可以独立使用或与其他功能结合使用。如果只想更改某个方法,那么其他的方法都是可以复用的。

    const makeToast = bread => spreadButter(sliceBread(bread));
    console.log(makeToast("White Bread")); 
    
    • 1
    • 2

    高阶函数

    JavaScript 中,接受其他函数作为参数或返回函数的函数称为高阶函数。它们是功能组合的基础。

    // 组合两个函数
    const compose = (f, g) => x => f(g(x));
    
    const makeSandwich = compose(addFilling, compose(spreadButter, sliceBread));
    
    console.log(makeSandwich("meat")); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    闭包

    JavaScript 中的闭包允许函数从封闭范围访问变量,即使在外部函数完成执行之后也是如此。这个概念在函数组合中特别有用,可以维护不同函数调用之间的状态。

    const addTopping = topping => bread => `${topping} added to ${bread}`;
    const addLettuce = addTopping("Lettuce");
    console.log(addLettuce("Butter spread on Whole Wheat is sliced")); 
    
    • 1
    • 2
    • 3

    一些三方库

    通过了解前面的内容,我们已经了解了函数组合的基本内容。不过我们在开发的时候可以选择一些三方库来更好的完善。比如RamdaLodash/fp等库。这些库提供了一套实用函数,使 JavaScript 中的函数式编程和函数组合更易于访问和管理。

    Ramda示例:

    import R from 'ramda';
    
    const sliceBread = bread => `${bread} is sliced`;
    const spreadButter = bread => `Butter spread on ${bread}`;
    const addFilling = bread => `Filling added to ${bread}`;
    
    const makeSandwich = R.compose(addFilling, spreadButter, sliceBread);
    
    console.log(makeSandwich("Sourdough"));  // "Filling added to Butter spread on Sourdough is sliced"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    TypeScript 和函数组合

    TypeScript JavaScript 的超集,它带来了静态类型。在 TypeScript 中使用函数组合时,类型添加了额外的安全层,确保组合链中的每个函数都遵守特定的约定。

    以下是在 TypeScript 中定义compose函数的示例:

    function compose<A, B, C>(f: (b: B) => C, g: (a: A) => B): (a: A) => C {
      return (x: A) => f(g(x));
    }
    
    const sliceBread = (bread: string) => `${bread} is sliced`;
    const spreadButter = (bread: string) => `Butter spread on ${bread}`;
    const addFilling = (bread: string) => `Filling added to ${bread}`;
    
    const makeSandwich = compose(addFilling, compose(spreadButter, sliceBread));
    
    console.log(makeSandwich("Multigrain"));  // "Filling added to Butter spread on Multigrain is sliced"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    隐式编程

    隐式编程强调定义函数而不明确提及它们的参数。在 JavaScript 中,高阶函数(将其他函数作为参数或返回它们的函数)在实现这一目标方面发挥着重要作用。

    正常编程:

    const double = x => x * 2;
    const increment = x => x + 1;
    
    const transform = x => increment(double(x));
    
    • 1
    • 2
    • 3
    • 4

    隐式编程

    const double = x => x * 2;
    const increment = x => x + 1;
    
    const compose = (f, g) => x => f(g(x));
    
    const transform = compose(increment, double);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里,compose函数是主要参与者,允许我们链接increment和double并且无需显式引用它们的参数。当我们调用transform时,它会通过doubleincrement两个函数处理输入,并且不会明确详细说明数据如何在这些函数之间流动。

    好处:

    1. 简洁:减少冗长,重点关注操作而不是数据。
    2. 可读性:代码强调转换过程,使其更具声明性。
    3. 可重用性:抽象出特定的参数会产生更通用和可重用的函数。
  • 相关阅读:
    go的切片扩容机制
    基于vue的tiptap编辑器插件(一)
    09—DOM和BOM
    CTF —— 网络安全大赛(这不比王者好玩吗?)
    StringBuilder 和 StringBuffer:Java字符串处理的利器
    16、探究 Java 动态绑定机制和 this 的本质
    更优雅的OrientDB Java API
    获取本地上传文件信息
    浅谈电源TLVR在Intel VR14 Server的应用
    亲爱的朋友
  • 原文地址:https://blog.csdn.net/qq_42880714/article/details/133625615