【问题标题】:How to use pattern matching without switch case in javascript (in functional programming way)如何在javascript中使用不带switch case的模式匹配(以函数式编程方式)
【发布时间】:2020-09-22 09:34:41
【问题描述】:

我一直在阅读要求使用 switch case 消除的干净代码书,所以我想在 JavaScript 中实现它,并且我想以函数式编程的方式使用它,所以我决定使用模式匹配。

我有下面的代码,我想省略switch case,我该怎么做,不使用多态。

function calculateSalary(role) {
    switch (true) {
      case /CTO/.test(role):
        return getCTOSallary();
      case /CEO/.test(role):
        return getCEOSallary();
      case /engineer/.test(role):
        return getEngineeringSallary();
      default:
        return getGeneralSallary();
    }
}

【问题讨论】:

  • 模式匹配只与正则表达式远程相关。无论如何,这两个概念都是基于统一两个术语而不是依赖于相等的想法。 Javascript 不包括模式匹配。您可能会为原生类型开发一个统一算法,但它会非常低效并且可能仍然难以使用。
  • 顺便说一句,建议避免使用switch 声明通常是荒谬的。
  • 您可以在某种程度上伪造自定义数据类型的模式匹配,就像daggy 一样。但是这个技巧只适用于标记的构造函数。

标签: javascript functional-programming switch-statement pattern-matching


【解决方案1】:

一种方法是使用dynamic dispatch

const Engineer = (name, bonus) => ({ constructor: Engineer, name, bonus });

Engineer.calculateSalary = engineer => 20 + engineer.bonus;

const Employee = (name, bonus) => ({ constructor: Employee, name, bonus });

Employee.calculateSalary = employee => 10 + employee.bonus;

const calculateSalary = role => role.constructor.calculateSalary(role);

console.log("John's salary is", calculateSalary(Engineer("John", 10))); // 30
console.log("Mary's salary is", calculateSalary(Employee("Mary", 10))); // 20

请注意,我们也可以使用类进行动态调度。然而,我想表明,使用纯函数式编程风格,可以在不使用类的情况下进行动态调度。

【讨论】:

    【解决方案2】:

    免责声明:我是此答案中提到的库的作者。


    我喜欢在 Clojure 中使用 multimethods 完成的方式:

    Clojure 多方法是调度函数和一个或多个方法的组合。

    1. 调度函数接受参数并返回一个值
    2. 分派的值用于确定调用哪个方法

    @customcommander/multifun 尝试将多方法引入 JavaScript。

    你首先需要一个调度函数

    这将是getRole。如果角色未知,它会返回您感兴趣的部分或null

    const getRole = role => {
      const match = role.match(/(cto|ceo|engineer)/i);
      return match ? match[1].toLowerCase() : null;
    };
    

    那么你需要一系列的价值/功能对

    • 'cto', getCTOSalary
    • 'ceo', getCEOSalary
    • ...

    最后你需要一个没有匹配的函数

    这将是 getGeneralSalary 函数。

    它是如何工作的?

    • getRole是调度函数,作用于参数并返回值
    • 将分派的值与每个 value/function 对中的值进行比较。
    • 如果匹配,则将函数应用于参数
    • 函数getGeneralSalary 在没有匹配项时应用于参数。

    const multifun = require("@customcommander/multifun");
    
    const getCTOSalary = (_, {bonus = 0}) => 10 + bonus;
    const getCEOSalary = (_, {bonus = 0}) => 20 + bonus;
    const getEngineeringSalary = (_, {bonus = 0}) => 30 + bonus;
    const getGeneralSalary = (_, {bonus = 0}) => 40 + bonus;
    
    const getRole = role => {
        const match = role.match(/(cto|ceo|engineer)/i);
        return match ? match[1].toLowerCase() : null;
    };
    
    const calculateSalary =
        multifun
            (   getRole
            ,   'cto', getCTOSalary
            ,   'ceo', getCEOSalary
            ,   'engineer', getEngineeringSalary
            ,   getGeneralSalary
            );
    
    calculateSalary('Chief Technology Officer (CTO)', {bonus: 1}); //=> 11
    calculateSalary('Chief Executive Officer (CEO)', {bonus: 2});  //=> 22
    calculateSalary('Senior Software Engineer', {bonus: 3});       //=> 33
    calculateSalary('random title', {bonus: 4});                   //=> 44
    

    【讨论】:

      【解决方案3】:

      你的意思是这样的吗?

      function test(str) {
         let tests = [/xyz/, /test/, /ing/];
         if(tests.some(patt => patt.test(str))) {
            console.log("Match found");
         }else {
            console.log("No match found");
         }
      }
      
      test("testing");

      【讨论】:

      • 其实这是一个例子,结果可以是不同的功能,比如根据公司的不同角色计算薪水,角色变成模式并根据它选择不同的功能
      猜你喜欢
      • 1970-01-01
      • 2011-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-17
      • 1970-01-01
      相关资源
      最近更新 更多