Home > Back-end >  Looking for a clean function implementation of a switch statement in JavaScript
Looking for a clean function implementation of a switch statement in JavaScript

Time:06-17

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.";
}

CodePudding user response:

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"));

CodePudding user response:

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"));

CodePudding user response:

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)

CodePudding user response:

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;}

CodePudding user response:

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"));

CodePudding user response:

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.
  • Related