21
头图

There are four ways to write switch in JavaScript, you know? Whether you know it or not, I don't know anyway.

There is only one way to write a switch statement in JavaScript that I know of. But when it comes to the processing of branches, there are many ways to write. The if branch writing method can be regarded as one type, the switch branch writing method can be regarded as the second type, and the third method is to use the strategy mode. If you want to include the conditional operator, well, there are exactly four.

But the protagonist of this article is the switch. We all know that the way switch is written is generally switch variables or expressions, case constants. Well, for example, a score of 90 and above is considered excellent, 80 and above is considered good, 60 and above below 80 is considered qualified, and below 60 is considered unqualified. Using switch, it would be written like this:

 function calcGrade(score) {
    const line = score / 10 | 0;
    switch (line) {
        case 10: case 9:
            return "优秀";
        case 8:
            return "良好";
        case 7: case 6:
            return "合格";
        default:
            return "不合格";
    }
}
In the code score / 10 | 0 and Math.floor(score / 10) have the same effect, which is the integer part of the quotient divided by 10.

This switch is used quite well, and it is also a trick to use the rounding method to avoid using a long series of if ... else branches.

But now that the rules have changed and the point of separation between pass and good has been lowered from 80 to 75, what to do?

The above method of rounding is still possible, but this time the divisor is no longer 10, but 5. Correspondingly, there are many more cases:

  • 18, 19, 20 are excellent
  • 15, 16, 17 are good
  • 12, 13, 14 are qualified
  • The rest are ineligible

Write 9 cases, it's better to use if...else.

Yeah? In fact, there is a simpler way to use switch:

 function calcGrade(score) {
    switch (true) {
        case score >= 90:
            return "优秀";
        case score >= 75:
            return "良好";
        case score >= 60:
            return "合格";
        default:
            return "不合格";
    }
}

Feeling a little weird? This is not at all the accustomed switch expression case constant, but the exact opposite, the switch constant case expression! If you take this program to run, you will find that there is no problem at all. Because -- switch and case are matched according to === , it doesn't care whether it is an expression or a constant, or in other words, both switch and case can be followed by an expression!

Yes, expressions!

So in the above example, changing switch(true) to switch( 2 > 1) has the same effect.

Alright, my brain is open. It doesn't matter how many ways switch is written. The next thing to study is a variant of switch -

Seeing that C# has a switch expression, I am jealous, can it be implemented?

Don't be greedy, everything in JavaScript can be an expression... If not, just wrap one with an IIFE

 function calcGrade(score) {
    return (value => {
        switch (true) {
            case value >= 90:
                return "优秀";
            case value >= 75:
                return "良好";
            case value >= 60:
                return "合格";
            default:
                return "不合格";
        }
    })(score);
}

Note that here score is used as the parameter of IIFE, because in actual use, an expression may need to be passed in. In this case it should be evaluated early and only once (to avoid the side effects of substitution).

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: "优秀" },
            { t: n => n >= 75, v: "良好" },
            { t: n => n >= 60, v: "合格" },
            { t: () => true, v: "不合格" },
        ]
    );
}

Each policy is an object containing a tester ( t ) and a value ( v ). tester is a judgment function, passing in the value to be judged, that is switch (表达式) here expression, and this expression is also passed in as a parameter of IIFE after pre-evaluation. The process of applying the strategy is simple and rude, that is, to find the first strategy that meets the conditions, and take out its value.

Of course, this strategy is a bit overkill. When a strategy is really needed, the strategy is usually not a value, but a behavior, that is, a function.

We know that in a switch statement, each case is in the same scope, so we cannot declare the same local variable in two case statements. Although wrapping with { } can solve these problems, the code does not look very good, especially pay attention 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, in the policy behavior, the grade will be output first, and then the grade 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 = "优秀";
                    console.log(grade, score);
                    return grade;
                }
            },
            {
                t: n => n >= 75,
                fn: score => {
                    const grade = "良好";
                    console.log(grade, score);
                    return grade;
                }
            },
            {
                t: n => n >= 60,
                fn: score => {
                    const grade = "合格";
                    console.log(grade, score);
                    return grade;
                }
            },
            {
                t: () => true,
                fn: score => {
                    const grade = "不合格";
                    console.log(grade, score);
                    return grade;
                }
            },
        ]
    );
}

The code is indeed a bit long, because there is policy behavior logic in it. If it is really used as a switch expression , the strategy part should be an expression and not too long. In the above code, the policy behavior is similar and can be encapsulated as 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("优秀", score) },
            { t: n => n >= 75, fn: score => printGrade("良好", score) },
            { t: n => n >= 60, fn: score => printGrade("合格", score) },
            { t: () => true, fn: score => printGrade("不合格", score) },
        ]
    );
}

Does it look good now?

The above codes are in different forms, and they do the same thing, and there is no comparison between who is better and who is worse. What is pleasing to the eye is elegant, and what is not pleasing to the eye is not favored. In different situations, it is good to choose the appropriate method. The above code uses find() to find the policy. If you use filter() instead, it will be another scene ~(~ ̄▽ ̄)~ .


边城
59.8k 声望29.6k 粉丝

一路从后端走来,终于走在了前端!