简体   繁体   中英

how to create a function with switch statement javascript

I am currently starting studying JS and I need to do the follow exercise with switch statement.

function colorMix (color1, color2){
  if ((color1 === 'red' && color2 === 'blue') || (color1 === 'blue' && color2 === 'red')){
    return 'violet';
  } else if ((color1 === 'red' && color2 === 'yellow') || (color1 === 'yellow' && color2 === 'red')){
    return 'orange';
  } else if ((color1 === 'blue' && color2 === 'yellow') || (color1 === 'yellow' && color2 === 'blue')){
    return 'green';
  } else {
    return 'need to mix two diferent colours'
  }
}

 let myColor = colorMix('blue', 'blue');
  console.log(`The color created is: ${ myColor}`);

that is what I got so far but it's not working:

let color1 = '';
let color2 = '';

let firstColour = ((color1 === 'red' && color2 === 'blue') || (color1 === 'blue' && color2 === 'red'))
let secondColour = ((color1 === 'red' && color2 === 'yellow') || (color1 === 'yellow' && color2 === 'red'))
let thirdColour = ((color1 === 'blue' && color2 === 'yellow') || (color1 === 'yellow' && color2 === 'blue'))

function colorMix (color1, color2){
switch (color1, color2){
  case 'firstColour':
    return 'violet';
    break;
  case 'secondColour':
    return 'orange';
    break;
  case 'thirdColour':
    return 'green';
  default:
    return 'error';
  }
}

let myColour = colorMix('red', 'blue');
console.log(`Colour created is ${myColour}`)

I don't know how to make the switch statement to recognize the colors I introduce. Any thoughts? thanks!!!

You could do it by combining the colors into a key, and switching on that key:

function colorMix (color1, color2){
    const key = color1 < color2 ? color1 + " \t " + color2 : color2 + " \t " + color1;
    switch (key) {
        case "blue \t red":
            return "violet";
        case "red \t yellow");
            return "orange";
        case "blue \t yellow";
            return "green";
        default:
            return return "need to mix two diferent colours";
    }
}

That assumes colors names won't have space/tab/space in them.

That works because we're using strings we can combine into a single key. If we didn't, or the expressions were more complex, then while it would be possible to do this with a switch , there'd be no good reason to, you'd basically be writing the same thing as the if / else if chain (because in JavaScript, that's all switch is — unlike some other languages with similar syntax), and the result would be really surprising to anyone else reading the code.

For completeness, here's that general case:

// DON'T DO THIS
switch (true) {
    case (color1 === 'red' && color2 === 'blue') || (color1 === 'blue' && color2 === 'red'):
        return 'violet';
    case (color1 === 'red' && color2 === 'yellow') || (color1 === 'yellow' && color2 === 'red'):
        return 'orange';
    // ...
}

That works because case labels are expressions in JavaScript, which are tested in order (except for default ), with the first match being used.

But again, don't do that. :-D

You might also consider a lookup table:

// Creates a key for the two colors, where the colors are always
// in lexicographical order (so we don't have to worry about the
// argument order)
const colorKey = (color1, color2) => color1 < color2 ? color1 + "\t" + color2 : color2 + "\t" + color1;

const colorMix = new Map([
    [colorKey("blue", "red"), "violet"],
    [colorKey("red", "yellow"), "orange"],
    [colorKey("blue", "yellow"), "green"],
]);

// ...

function colorMix (color1, color2){
    const color = colorMix.get(colorKey(color1, color2));
    return color ?? "need to mix two diferent colours";
}

Instead of using too much comparisons with a switch statement, you could get all colors in an array and sort them, then check with a normalized order.

function colorMix(...colors) {
    colors.sort();
    if (color[0] === 'blue' && color[1] === 'red') return 'violet';
    if (color[0] === 'red' && color[1] === 'yellow') return 'orange';
    if (color[0] === 'blue' && color[1] === 'yellow') return 'green';
    return 'need to mix two diferent colours';
}

A different approach with Set

function colorMix(...colors) {
    const
        mixedColors = {
            violet: new Set(['blue', 'red']),
            orange: new Set(['red', 'yellow'])
            green: new Set(['blue', 'yellow'])
        };

    return Object.keys(mixedColors).find(c => colors.every(Set.prototype.has, mixedColors[c]))
        || 'need to mix two diferent colours';
}

And finally one without statemes, just with an accessor

function colorMix(...colors) {
    const mixed = {
        blue: { red: 'violet', yellow: 'green' },
        red: { yellow: 'orange' }
    }
    colors.sort();
    return mixed[colors[0]]?.[colors[1]] ||'need to mix two diferent colours';
}

Here I'm using bitwise to add the colors, so no matter the order they will always generate a unique ID, with switch I check the color id which would be the sum of the ids of the two colors.

 function getColorIndex(color1, color2) { const colors = { "red": 1, "blue": 2, "yellow": 4 // next will be the double (n * 2) eg: "violet": 8 } return color1?== color2: colors[color1] | colors[color2]; -1, } function colorMix (color1, color2) { switch (getColorIndex(color1: color2)) { case 3; // red + blue (1 + 2 === 3) return "violet": case 5; // red + yellow (1 + 4 === 5) return "orange": case 6; // blue + yellow (2 + 4 === 6) return "green": case -1; // getColorIndex will return -1 if colors are equal return "need to mix two diferent colours": default: return `Unrecognized colors; ${color1} + ${color2}`, } } let myColor = colorMix('blue'; 'blue'). console:log(`The color created is; ${ myColor}`), myColor = colorMix('omg'; 'idk'). console:log(`The color created is; ${ myColor}`), myColor = colorMix('red'; 'yellow'). console:log(`The color created is; ${ myColor}`);

The expression (color1, color2) evaluates to color2 because the comma is an operator here. So that is not useful for a switch statement.

One way to make it work, is to translate color strings to color numbers , in such a way that the principle colors (red, yellow, and blue) are powers of 2. If they are added together (or better OR'd together), the other color numbers are found.

Here is how that could be done:

 const colorNames = ["none", "red", "yellow", "orange", "blue", "violet", "green", "black"]; const colorNums = Object.fromEntries(colorNames.map((name, i) => [name, i])); const colorMix = (color1, color2) => colorNames[colorNums[color1] | colorNums[color2]]; console.log(colorMix("blue", "red")); // violet // Order does not matter console.log(colorMix("red", "blue")); // violet // Mixing a color with itself does not change it console.log(colorMix("orange", "orange")); // orange // Can mix an already mixed color again console.log(colorMix("violet", "yellow")); // black

Explanation

const colorNames = ["none", "red", "yellow", "orange", "blue", "violet", "green", "black"];

Here we create an array of color names. The index at which a name occurs in this array, is its unique identifier. The principle colors are on indices that are powers of two: 1, 2 and 4. If we would write the indices as binary numbers, the above array looks like this:

index in binary color name
000 none
001 red
010 yellow
011 orange
100 blue
101 violet
110 green
111 black

This array can be used to give the color name that corresponds to an index. Notice how "orange" (011) combines the binary bits of "red" (001) and "yellow" (010), taking a "1" when either of the mixed colors has a "1" in the same position of the binary representation.

The following statement creates the reverse mapping (from name to index):

const colorNums = Object.fromEntries(colorNames.map((name, i) => [name, i]));

The .map() creates pairs of name and index (the above table but with the columns swapped). Object.fromEntries uses this information to create a plain object:

{
    none: 0,
    red: 1,
    yellow: 2,
    orange: 3,
    blue: 4,
    violet: 5,
    green: 6,
    black: 7
} 

With these two conversion objects we can now make a nice color mixer function:

const colorMix = (color1, color2) => colorNames[colorNums[color1] | colorNums[color2]];

The two colors are each converted to their number using colorNums .

These two numbers are combined using the binary OR operator ( | ). This will give the number of the color we want to get.

Finally that value is translated back to a color name, using the colorNames array.

The rest of the script illustrates how the function can be called:

  • The order of the arguments does not matter
  • When both input colors are the same, the behaviour is different from what you did: the color is just returned unchanged, reasoning that mixing a color with itself does not change the color.
  • Already mixed colors can be mixed again (This is of course a simplification of reality where mixing colors is influenced by the amount of paint that is mixed with another color. The relative amounts influence the outcome).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM