在JavaScript中寻找切换语句的干净函数实现

发布于 2025-02-08 08:54:42 字数 1134 浏览 2 评论 0原文

我正在教授一门课程,其中包括解释功能性JavaScript,我想拥有一个非常好的功能编程的例子,该功能编程希望比非功能更清洁。我想将以下开关语句转换为功能。我自己以这种转换为例,但是希望有一个简单的解决方案。

这是Switch语句版本:

let animalType = "Poodle";
switch (animalType) {
  case "Poodle":
  case "Beagle":
  case "Bulldog":
    console.log(animalType + " is a dog.");
    break;
  case "Bengal":
  case "Siamese":
    console.log(animalType + " is a cat.");
    break;
  default:
    console.log(animalType + " is not a dog or cat.");
    break;
}

这就是我想出的功能,我对

const result = getAnimalType("Poodle");
console.log("result:" + result)

function getAnimalType(animal) {
  function isDog(animal) {
    const dogs = ["Poodle", "Beagle", "Bulldog"];
    return dogs.includes(animal)
  }
  function isCat(animal) {
    const cats = ["Bengal", "Siamese"];
    return cats.includes(animal)
  }
  return isDog(animal)
    ? animal + " is a dog."
    : isCat(animal)
    ? animal + " is a cat."
    : animal + " is not a dog or cat.";
}

I am teaching a course that includes explaining functional JavaScript and I want to have a really good example of functional programming that is hopefully cleaner then non-functional. I want to convert the following switch statement to functional. I've made an example of that conversion myself, but hoping there is a simpler solution.

Here is the switch statement version:

let animalType = "Poodle";
switch (animalType) {
  case "Poodle":
  case "Beagle":
  case "Bulldog":
    console.log(animalType + " is a dog.");
    break;
  case "Bengal":
  case "Siamese":
    console.log(animalType + " is a cat.");
    break;
  default:
    console.log(animalType + " is not a dog or cat.");
    break;
}

And here is what I came up with as functional that I'm not that happy about

const result = getAnimalType("Poodle");
console.log("result:" + result)

function getAnimalType(animal) {
  function isDog(animal) {
    const dogs = ["Poodle", "Beagle", "Bulldog"];
    return dogs.includes(animal)
  }
  function isCat(animal) {
    const cats = ["Bengal", "Siamese"];
    return cats.includes(animal)
  }
  return isDog(animal)
    ? animal + " is a dog."
    : isCat(animal)
    ? animal + " is a cat."
    : animal + " is not a dog or cat.";
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

你不是我要的菜∠ 2025-02-15 08:54:42

您可以使用对象将动物类型映射到功能。

function dog(animalType) {
  return animalType + " is a dog.";
}

function cat(animalType) {
  return animalType + " is a cat.";
}

function other(animalType) {
  return animalType + " is not a dog or cat.";
}

const typeMap = {
  Poodle: dog,
  Beagle: dog,
  Bulldog: dog,
  Bengal: cat,
  Siamese: cat
};

function getAnimalType(animalType) {
  let typeFun = typeMap[animalType] || other;
  return typeFun(animalType);
}

console.log(getAnimalType("Poodle"));

You can use an object to map animal types to functions.

function dog(animalType) {
  return animalType + " is a dog.";
}

function cat(animalType) {
  return animalType + " is a cat.";
}

function other(animalType) {
  return animalType + " is not a dog or cat.";
}

const typeMap = {
  Poodle: dog,
  Beagle: dog,
  Bulldog: dog,
  Bengal: cat,
  Siamese: cat
};

function getAnimalType(animalType) {
  let typeFun = typeMap[animalType] || other;
  return typeFun(animalType);
}

console.log(getAnimalType("Poodle"));

嘿哥们儿 2025-02-15 08:54:42

一种选择是由狗或猫索引的对象,其值是动物类型的阵列。这对于其他动物类型很容易扩展。

const animalNamesByType = {
  dog: ["Poodle", "Beagle", "Bulldog"],
  cat: ["Bengal", "Siamese"]
};
function getAnimalType(animal) {
  const entry = Object.entries(animalNamesByType).find(
    entry => entry[1].includes(animal)
  );
  return entry
  ? `${animal} is a ${entry[0]}`
  : `${animal} is not in animalNamesByType`;
}
console.log(getAnimalType("Poodle"));

One option is an object indexed by dog or cat, whose values are arrays of animal types. This is easily extensible to additional animal types.

const animalNamesByType = {
  dog: ["Poodle", "Beagle", "Bulldog"],
  cat: ["Bengal", "Siamese"]
};
function getAnimalType(animal) {
  const entry = Object.entries(animalNamesByType).find(
    entry => entry[1].includes(animal)
  );
  return entry
  ? `${animal} is a ${entry[0]}`
  : `${animal} is not in animalNamesByType`;
}
console.log(getAnimalType("Poodle"));

爱的故事 2025-02-15 08:54:42

您可以为此创建一个非常简单的3线功能

const dogs = ["Poodle", "Beagle", "Bulldog"];
const cats = ["Bengal", "Siamese"];

const getAnimalType = (animal) => {
  if(dogs.includes(animal)) return `${animal} is a dog`
  if(cats.includes(animal)) return `${animal} is a cat`
  return `${animal} is not a dog or cat.`
}

const result = getAnimalType("Poodle");
console.log("result:" + result)

You can create a really simple 3-line function for this

const dogs = ["Poodle", "Beagle", "Bulldog"];
const cats = ["Bengal", "Siamese"];

const getAnimalType = (animal) => {
  if(dogs.includes(animal)) return `${animal} is a dog`
  if(cats.includes(animal)) return `${animal} is a cat`
  return `${animal} is not a dog or cat.`
}

const result = getAnimalType("Poodle");
console.log("result:" + result)
秋日私语 2025-02-15 08:54:42

一个变体,有点像Barmar的变体,但对我来说仍然是个人的

const getAnimalType = (() => 
  {
  const
    isX =
    { dog : 'is a dog'
    , cat : 'is a cat'
    , nDC : 'is neither a dog nor a cat'
    }
  , typeMap = 
    { Poodle  : 'dog'
    , Beagle  : 'dog'
    , Bulldog : 'dog'
    , Bengal  : 'cat'
    , Siamese : 'cat'
    };
  return (animal) => `${animal} ${isX[ typeMap[animal] ?? 'nDC']}`
  })()

console.log(getAnimalType('Beagle'))
console.log(getAnimalType('Bengal'))
console.log(getAnimalType('schtroumpf'))
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}

a variant, a bit like Barmar's, but which remains personal to me

const getAnimalType = (() => 
  {
  const
    isX =
    { dog : 'is a dog'
    , cat : 'is a cat'
    , nDC : 'is neither a dog nor a cat'
    }
  , typeMap = 
    { Poodle  : 'dog'
    , Beagle  : 'dog'
    , Bulldog : 'dog'
    , Bengal  : 'cat'
    , Siamese : 'cat'
    };
  return (animal) => `${animal} ${isX[ typeMap[animal] ?? 'nDC']}`
  })()

console.log(getAnimalType('Beagle'))
console.log(getAnimalType('Bengal'))
console.log(getAnimalType('schtroumpf'))
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}

给妤﹃绝世温柔 2025-02-15 08:54:42

从功能编程的角度来看,switch没有错。问题是,它将console.log称为副作用,而不是返回值。但是,易于修复:

function getAnimalType(animalType) {
  switch (animalType) {
    case "Poodle":
    case "Beagle":
    case "Bulldog":
      return animalType + " is a dog.";
    case "Bengal":
    case "Siamese":
      return animalType + " is a cat.";
    default:
      return animalType + " is not a dog or cat.";
  }
}

console.log(getAnimalType("Poodle"));

下一个改进可能避免重复:

function getAnimalType(animalType) {
  switch (animalType) {
    case "Poodle":
    case "Beagle":
    case "Bulldog":
      return "a dog";
    case "Bengal":
    case "Siamese":
      return "a cat";
    default:
      return "not a dog or cat";
  }
}
function getStatement(animalType) {
  return animalType + " is " + getAnimalType(animalType) + ".";
}
console.log(getStatement("Poodle"));

There's nothing wrong with switch from the perspective of functional programming. The problem rather is that it calls console.log as a side effect, instead of returning a value. Easy to fix, though:

function getAnimalType(animalType) {
  switch (animalType) {
    case "Poodle":
    case "Beagle":
    case "Bulldog":
      return animalType + " is a dog.";
    case "Bengal":
    case "Siamese":
      return animalType + " is a cat.";
    default:
      return animalType + " is not a dog or cat.";
  }
}

console.log(getAnimalType("Poodle"));

Next improvement might be avoiding some duplication:

function getAnimalType(animalType) {
  switch (animalType) {
    case "Poodle":
    case "Beagle":
    case "Bulldog":
      return "a dog";
    case "Bengal":
    case "Siamese":
      return "a cat";
    default:
      return "not a dog or cat";
  }
}
function getStatement(animalType) {
  return animalType + " is " + getAnimalType(animalType) + ".";
}
console.log(getStatement("Poodle"));
九命猫 2025-02-15 08:54:42

在这种情况下,使用地图将是我首选的选择。问题是如何。我喜欢咖喱功能,所以我会使用这些功能:

const animalType =
  (type => animal =>
    type[animal]
      ? `${animal} is a ${type[animal]}`
      : `${animal} is neither a dog nor a cat`)
    ({ Poodle:  'dog'
     , Beagle:  'dog'
     , Bulldog: 'dog'
     , Bengal:  'cat'
     , Siamese: 'cat'});

animalType('Poodle');
//> 'Poddle is a dog'

这里发生了什么?

我们有一个函数获取地图,然后返回一个函数,该功能最终接收动物并返回消息。关键是要意识到我们还使用IIFE:

const animalType =
  (type => animal => {/*…*/})({Poodle: 'dog'});
// ^^^^                       ^^^^^^^^^^^^^^^
// |                          |
// +--------------------------+

函数AnimalType是“硬编码”来与我们提供的type一起使用的。现在,它只是等待Animal参数进来。

但是,这似乎是我们可以抽象和重复使用的东西:

const lookup =
  (pass, fail, map) => key =>
    key in map
      ? pass(key, map[key])
      : fail(key);

lookup功能取得成功函数Pass 和失败函数失败和初始地图。然后,它返回一个<代码>键并将Pass应用于键>键和相应值(如果密钥存在于地图中的)的函数。否则,它将Fail应用于密钥。

因此,我们可以以这种方式构建AnimalType

const animalType =
  lookup( (key, val) => `${key} is a ${val}`
        , (key) => `${key} is neither a dog nor a cat`
        , { Poodle:  'dog'
          , Beagle:  'dog'
          , Bulldog: 'dog'
          , Bengal:  'cat'
          , Siamese: 'cat'});

animalType('Poodle');
//> 'Poddle is a dog'

Working with maps would be my preferred option in this case. The question is how. I like curried functions so I'll use those:

const animalType =
  (type => animal =>
    type[animal]
      ? `${animal} is a ${type[animal]}`
      : `${animal} is neither a dog nor a cat`)
    ({ Poodle:  'dog'
     , Beagle:  'dog'
     , Bulldog: 'dog'
     , Bengal:  'cat'
     , Siamese: 'cat'});

animalType('Poodle');
//> 'Poddle is a dog'

What's going on here?

We have a function that takes a map then returns a function that finally takes an animal and returns a message. The key is to realise that we also use an IIFE:

const animalType =
  (type => animal => {/*…*/})({Poodle: 'dog'});
// ^^^^                       ^^^^^^^^^^^^^^^
// |                          |
// +--------------------------+

The function animalType is "hardcoded" to work with the type we gave it. Now it just waits for the animal parameter to come in.

However this seems like something we could abstract and reuse:

const lookup =
  (pass, fail, map) => key =>
    key in map
      ? pass(key, map[key])
      : fail(key);

The lookup function takes a success function pass and a failure function fail and an initial map. Then it returns a function that takes a key and applies pass to key and the corresponding value if the key exists in the map. Otherwise it applies fail to the key.

With that we can build animalType this way:

const animalType =
  lookup( (key, val) => `${key} is a ${val}`
        , (key) => `${key} is neither a dog nor a cat`
        , { Poodle:  'dog'
          , Beagle:  'dog'
          , Bulldog: 'dog'
          , Bengal:  'cat'
          , Siamese: 'cat'});

animalType('Poodle');
//> 'Poddle is a dog'
不弃不离 2025-02-15 08:54:42

通过编译打字稿枚举代码示例,我得到了与此类似的东西:

var AnimalType;
(function (AnimalType) {
    AnimalType[AnimalType["Poodle"] = 0] = "Poodle";
    AnimalType[AnimalType["Beagle"] = 1] = "Beagle";
    AnimalType[AnimalType["Bulldog"] = 2] = "Bulldog";
    AnimalType[AnimalType["Bengal"] = 3] = "Bengal";
    AnimalType[AnimalType["Siamese"] = 4] = "Siamese";
})(AnimalType || (AnimalType = {}));

function whichKind(animalType) {
    let kind;
    switch (animalType) {
        case AnimalType.Poodle:
            kind = `${AnimalType[animalType]} is a dog`;
            break;
        case AnimalType.Beagle:
            kind = `${AnimalType[animalType]} is a dog`;
            break;
        case AnimalType.Bulldog:
            kind= `${AnimalType[animalType]} is a dog`;
            break;
       case AnimalType.Bengal:
            kind = `${AnimalType[animalType]} is a cat`;
            break;
       case AnimalType.Siamese:
            kind = `${AnimalType[animalType]} is a cat`;
           break;
    }
 
    kind = typeof kind === 'undefined' ? `${animalType} is not a dog or cat.` : kind;

    return kind;
}

console.log(whichKind(AnimalType.Poodle)); // Poodle is a dog

// console.log(whichKind('Other')); // Other is not a dog or cat.

I get something similar to this by compiling a TypeScript enum code example:

var AnimalType;
(function (AnimalType) {
    AnimalType[AnimalType["Poodle"] = 0] = "Poodle";
    AnimalType[AnimalType["Beagle"] = 1] = "Beagle";
    AnimalType[AnimalType["Bulldog"] = 2] = "Bulldog";
    AnimalType[AnimalType["Bengal"] = 3] = "Bengal";
    AnimalType[AnimalType["Siamese"] = 4] = "Siamese";
})(AnimalType || (AnimalType = {}));

function whichKind(animalType) {
    let kind;
    switch (animalType) {
        case AnimalType.Poodle:
            kind = `${AnimalType[animalType]} is a dog`;
            break;
        case AnimalType.Beagle:
            kind = `${AnimalType[animalType]} is a dog`;
            break;
        case AnimalType.Bulldog:
            kind= `${AnimalType[animalType]} is a dog`;
            break;
       case AnimalType.Bengal:
            kind = `${AnimalType[animalType]} is a cat`;
            break;
       case AnimalType.Siamese:
            kind = `${AnimalType[animalType]} is a cat`;
           break;
    }
 
    kind = typeof kind === 'undefined' ? `${animalType} is not a dog or cat.` : kind;

    return kind;
}

console.log(whichKind(AnimalType.Poodle)); // Poodle is a dog

// console.log(whichKind('Other')); // Other is not a dog or cat.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文