There are four ways to write JavaScript switch, do you know? Whether you know it or not, I don’t know.
There is only one way to write the JavaScript switch statement that I know of. But when it comes to handling branches, there are many ways to write them. The if branch writing method can be counted as one, the switch branch writing method can be counted as the second, and the third is to use the strategy mode. If conditional operators are also included, well, there are exactly four.
but the protagonist of this article is switch. Everyone knows that switch is generally written as a switch variable or expression and a case constant. Well, for example, for a hundred-point score, 90 and above is considered excellent, 80 and above and below 90 are considered good, 60 and above and below 80 are considered qualified, and below 60 is considered unqualified. Using switch, it would probably be written like this:
function calcGrade(score ) { const line = score / 10 | 0; switch (line) { case 10: case 9: return "Excellent"; case 8: return "good"; case 7: case 6: return "qualified"; default: return "unqualified"; } }
In the code, score / 10 | 0
has the same effect as Math.floor(score / 10)
, which is to divide by 10 to get the integer part of the quotient.
This switch is used quite well, and the rounding method to avoid using a long list of if...else branches is also a clever trick.
But now the rules have changed and the separation point between qualified and good has been lowered from 80 points to 75 points. What should we do?
The above rounding method is still possible, but this time the divisor is no longer 10, but 5. Correspondingly, there are many more cases:
Write 9 cases. It is better to use if... else. .
Is it? In fact, there is a simpler way to write using switch:
function calcGrade(score) { switch (true) { case score >= 90: return "Excellent"; case score >= 75: return "good"; case score >= 60: return "qualified"; default: return "unqualified"; } }
Does it feel a little strange? This is not the usual switch expression case constant at all, but the exact opposite, switch constant case expression! If you take this program and run it, you will find that there is no problem at all. Because - switch and case are matched according to ===
, it does not care whether it is an expression or a constant, or in other words, switch and case can be followed by an expression!
Yes, expression!
So in the above example, changing switch(true)
switch( 2 > 1)
has the same effect.
Okay, my mind is open. It doesn’t matter how many ways you can write switch. The next thing to look at is the switch variant.
: I saw that C# has a switch expression, and I am jealous. Can it be implemented?
Don't worry, everything in JavaScript can be an expression... If not, just use IIFE to encapsulate one
function calcGrade(score) { return (value => { switch (true) { case value >= 90: return "Excellent"; case value >= 75: return "good"; case value >= 60: return "qualified"; default: return "unqualified"; } })(score); }
Note that score
is used as a parameter of IIFE here because in actual use, an expression may need to be passed in. In this case it should be evaluated in advance and only once (to avoid substitution side effects).
However, such encapsulation is obviously meaningless. If you really want to encapsulate it like this, it is better to encapsulate it as a strategy:
function calcGrade(score) { return ((value, rules) => rules.find(({ t }) => t(value)).v)( score, [ { t: n => n >= 90, v: "Excellent" }, { t: n => n >= 75, v: "Good" }, { t: n => n >= 60, v: "Qualified" }, { t: () => true, v: "unqualified" }, ] ); }
Each strategy is an object containing a tester ( t
) and a value ( v
). tester is a judgment function that passes in the value that needs to be judged, which is the expression here in switch (表达式)
, and this expression is also passed in as a parameter of IIFE after being evaluated in advance. The process of applying a strategy is simple and crude, which is to find the first strategy that meets the conditions and take out its value.
Of course, this strategy is a bit overkill. When you really need to use a strategy, the strategy is usually not a value, but a behavior, that is, a function.
We know that in the switch statement, each case is in the same scope, so the same local variable cannot be declared in two case statements. Although wrapping with { }
can solve these problems, the code does not look very good, especially be careful not to forget break
. If you use a strategy, it may look pleasing to the eye, and you don't have to worry about the break problem:
here for demonstration purposes, in the strategy behavior, the results will be output first, and then the level will be returned.
function calcGrade(score) { return ((value, rules) => rules.find(({ t }) => t(value)).fn(value))( score, [ { t: n => n >= 90, fn: score => { const grade = "Excellent"; console.log(grade, score); return grade; } }, { t: n => n >= 75, fn: score => { const grade = "good"; console.log(grade, score); return grade; } }, { t: n => n >= 60, fn: score => { const grade = "passed"; console.log(grade, score); return grade; } }, { t: () => true, fn: score => { const grade = "unqualified"; console.log(grade, score); return grade; } }, ] ); }
The code is indeed a bit long because there is strategic behavior logic in it. If it is really going to be used as a switch expression , the strategy part should be an expression, not too long. In the above code, the strategy behavior is similar and can be encapsulated into a function, so that it can be written in the form of an expression:
function calcGrade(score) { const printGrade = (grade, score) => { console.log(grade, score); return grade; }; return ((value, rules) => rules.find(({ t }) => t(value)).fn(value))( score, [ { t: n => n >= 90, fn: score => printGrade("Excellent", score) }, { t: n => n >= 75, fn: score => printGrade("Good", score) }, { t: n => n >= 60, fn: score => printGrade("qualified", score) }, { t: () => true, fn: score => printGrade("unqualified", score) }, ] ); }
Does it look presentable now?
The above codes have different forms and do similar things, and there is no comparison of which one is better. No matter what you like, you are elegant; no matter what you don't, you are not favored. In different situations, just choose the appropriate approach. The above code uses find()
to find the strategy. If filter()
is used instead, it will be a different story.