Alternative to the "switch" Statement
Asked Answered
O

9

29

I do not want to use Switch in my code, so I'm looking for some alternative

Example with Switch:

function write(what) {

  switch(what) {

    case 'Blue':
      alert ('Blue');
    break;

    ...

    case 'Red':
      alert ('Red');
    break;

  }

}

Example without Switch:

colors = [];

colors['Blue'] = function() { alert('Blue'); };
colors['Red'] = function() { alert('Red'); };


function write(what) {

  colors[what]();

}

My questions are:

  1. Do you know any other alternatives?
  2. Is this best solution?
Ole answered 21/2, 2010 at 19:32 Comment(3)
It's great. Leave it.Lonnalonnard
yes, that's better solution with lesser code :)Spoil
Its also cleaner, easier to read and possible could remove duplicative code.Kevinkevina
M
25

I have only a note about your second approach, you shouldn't use an Array to store non-numeric indexes (that you would call in other languages an associative array).

You should use a simple Object.

Also, you might want to check if the what argument passed to your write function exists as a property of your colors object and see if it's a function, so you can invoke it without having run-time errors:

var colors = {};

colors['Blue'] = function() { alert('Blue'); };
colors['Red'] = function() { alert('Red'); };


function write(what) {
  if (typeof colors[what] == 'function') {
    colors[what]();
    return;
  }
  // not a function, default case
  // ...
}
Midis answered 21/2, 2010 at 19:43 Comment(3)
With respect, I think the article you linked got it wrong. Rather, one shouldn't use for..in to iterate an array.Hathaway
@machine: That article also speaks about the for...in statement and the problems that come when the prototype member of built-in constructors like Array and Object is extended, but the bottom line of the article is that JavaScript arrays are meant to be numeric, and they are often used to store arbitrary key/value pairs which is bad practice...Charters
Bottom line? Using expando properties on an array doesn't change that fact. There's nothing to gain by turning one of most versatile objects at your disposal into the least versatile. I'm not sure why you say "The article also speaks"... My understanding is that the entire point of the article is to 'better' support use of for..in with Arrays.Hathaway
M
19

I used a structure like this today:

var chosenColor = 'red';

var colorString = {
    'red': 'The color is red.',
    'green': 'The color is green.',
    'blue': 'The color is blue.',
}[chosenColor] || 'The color is unknown.';

I like that it's a really small amount of code to choose a string based on choice.

You could also pass it to a function:

alert({
    'red': 'The color is red.',
    'green': 'The color is green.',
    'blue': 'The color is blue.',
}[chosenColor] || 'The color is unknown.');
Megdal answered 15/2, 2012 at 12:46 Comment(5)
short and simple, like it. +1Kymric
this is cool as long as the chosenColor exists in colorString. if chosenColor is 'orange' for example, you'll get a Type Error.Creed
In fact, you could easily add a default option with ({'red': 'the color is red'})[chosenColor] || 'default'Terranceterrane
Thanks @superzamp, I have edited my code to add the default option.Megdal
Use ?? instead of || in 2021.Norbert
A
3

You could use object literals, and try catch to trap the default:

function write(what) {
    var colors = {
    'Blue': function(){ alert('Light-Blue'); },
    'Red': function(){ alert('Deep-Red'); },
    'Green': function(){ alert('Deep-Green'); }
    }
    try {colors[what]();}
    catch(err) {colors['Green']();}//default behaviour
}
write('Pink');
Agrarian answered 14/1, 2011 at 22:25 Comment(0)
F
1

Question 2:

Generally, if you can replace custom control structures with a dictionary lookup, you're perfectly fine. It's easy to read and highly elegant -- stick with it.

Farfetched answered 21/2, 2010 at 19:37 Comment(0)
R
1

I had to do do a compare for a group sort of object props for a list and did not want to do a switch/case for all the possibilities so I did an array of objects assignment to a numeric rank first so the case became a simple compare. This is only 4 possibilities but you get the drift of how to extend this to situation where a switch/case becomes unmanageable:

function mySort2(item1,item2){

     var matrix = {  
    'repair': 4,  
    'r/r': 3,  
    'part': 2,  
    'misc': 1  
  };  

(matrix[item1.category] < matrix[item2.category]) ? return +1 : return -1;

// if possible bad data need to check for this first ???

i1=matrix[item1.category] || null;
i2=matrix[item2.category] || null;

if (i1==null){
    // handle bad data in item 1
    return +1; // put it after 2
}

if (i2==null){
    // ditto 
    return -1; //put 1 first
}

if (i1<i2) 
    return +1;
else 
    return -1;

}

Regalia answered 9/9, 2014 at 2:29 Comment(1)
Its an answer: an alternative to using a switch/case for this purpose. You could also use an [] of [] to have an actual matrix of values to return.Regalia
R
0

You are pretty much there already. If possible you might want to add a helper function to make the setup easier. For Example:

function setup(what)
{
    colors[what] = function() { alert(what); };
}

EDIT:
If what you want to do for each option is more complicated clearly this will not work. As mentioned in the comments by @roe this uses the global colors which is often frowned upon.

Rawinsonde answered 21/2, 2010 at 19:37 Comment(1)
This only works for this particular example, chances are they don't have that much in common in reality. Also colors is a global here, which is rarely a Good Thing.Irritant
R
0

Alternatively, you can also use Dictionaries, so you could see the type of the function return, I think it's clean and scalable, although it's just pure JS.

const ColorDictionary = {
  red: 'applies red color',
  blue: ' applies blue color',
  green: 'applies green color',
}

const useShowColors = (color) => {

 // color will be selected or fallout to default value.
 const getColor = () => (
  ColorDicionary[color] ?? 'applies default color' 
 )
 
 return { getColor }
}

const { getColor } = useShowColors() //pass the color you wish.
Rager answered 2/12, 2021 at 11:19 Comment(0)
H
-1

An alternative is to define a class with a write method, and override that in subclasses Red and Blue to do the right thing.

Whether or not that is better than your proposed solution, depends on your particular situation.

Hessenassau answered 21/2, 2010 at 19:36 Comment(0)
L
-1

As I said, it's great. The only thing I can add to your solution is that it's perhaps better to localize your colors.

function write(what) {
    var colors = [];
    colors['Blue'] = function() { alert('Blue'); };
    colors['Red'] = function() { alert('Red'); };
    colors[what]();
}
Lonnalonnard answered 21/2, 2010 at 19:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.