In the front-end JS coding process, you can’t avoid writing if-else or switch-case branch statements. The code style varies from person to person, but there are many ways to reduce some obscure conditional judgments and reduce nesting. Now let’s discuss from the front-end JS level: how to write branch conditions less and better?

1. Triadic operation for single condition

if (isTrue) {
    return 1;
}
return 2;
Copy the code

Ternary operation rewrite:

return isTrue ? 1 : 2;
Copy the code

2. Use logical operators && (and) and | | (or)

if (isTrue) {
    setTrueValue();
}

if(! isFalse) { setTrueValue(); }Copy the code

To rewrite using logical operators:

isTrue && setTrueValue();

isFalse || setTrueValue();
Copy the code

Note: try to avoid using ternary operations or logical operators to write more complex logic, to ensure good readability!

3. Use array.includes ()

function sayWords (role) {
    if (role === 'javascript' || role === 'go' || role === 'python' || role === 'java') {
        console.log('Hello World ~'); }}Copy the code

There is no problem with the logic of this writing method, and I believe that we are also more common, but this condition is particularly long and ugly.

Array.includes()

function sayWords (role) {
    const ROLES_SAY_HELLO = ['javascript'.'go'.'python'.'java'];

    if (ROLES_SAY_HELLO.includes(role)) {
        console.log('Hello World ~'); }}Copy the code

Obviously, the implementation logic looks much cleaner when we extract all the qualified characters into the array for maintenance, and even if we add conditions later, we just need to enrich the array.

Another multi-condition situation may have multiple dimensions, not only like the judgment of single value above, but also involves logical judgment, etc., for example:

if (sex === 'man' && age < 30 && hasRequiredProperty(property) && acountNumber.indexOf('666666')! = =- 1) {
    doSomething();
}
Copy the code

In this case, adding a condition directly after the if will reduce the readability of the code, so it is better to extract the condition into the variable one by one:


let isMan = sex === 'man',
    isAgeAgree = age < 30,
    hasRequiredProperty = hasRequiredProperty(property),
    isAcountAgree = acountNumber.indexOf('666666')! = =- 1;

// Note the special condition completion comment
let isAvailable = isMan && isAgeAgree && hasRequiredProperty && isAcountAgree;

isAvailable && doSomething();

Copy the code

Advantages: High code readability

4. Return early to reduce nesting

function sayWords (role) {
    if (typeof role === 'string') {
        const ROLES_SAY_HELLO = ['javascript'.'go'.'python'.'java'];

        if (ROLES_SAY_HELLO.includes(role)) {
            console.log('Hello World ~'); }}else {
        throw new Error('role type error! '); }}Copy the code

The writing is very consistent with our conventional way of thinking, but from the point of view of coding this code, we make the following improvements:

function sayWords (role) {

    // Invalid types throw exceptions
    if (typeofrole ! = ='string') {
        throw new Error('role type error! ');
    }

    const ROLES_SAY_HELLO = ['javascript'.'go'.'python'.'java'];

    if (ROLES_SAY_HELLO.includes(role)) {
        console.log('Hello World ~'); }}Copy the code

In this way, the first step is to throw the exception type error, which is equivalent to our regular return, so we reduce one layer of nesting of the main logic. Especially if the main logic is long, the advantage of this approach is obvious, as long as you always follow the invalid condition return early rule.

5. Make good use of JS functionsThe default parameters

function sayWords (role) {

    // Invalid types throw exceptions
    if (typeofrole ! = ='string') {
        throw new Error('role type error! ');
    }

    if(! role) { role ='javascript';
    }

    / / or: role = role | | 'javascript'

    const ROLES_SAY_HELLO = ['javascript'.'go'.'python'.'java'];

    if (ROLES_SAY_HELLO.includes(role)) {
        console.log('Hello World ~'); }}Copy the code

We also add a lot of logic to functions like the role default value above:

if(! role) { role ='javascript';
}
Copy the code

or

role = role || 'javascript'
Copy the code

By switching to function default parameters, we can omit this logic.

function sayWords (role = 'javascript') {

    // Invalid types throw exceptions
    if (typeofrole ! = ='string') {
        throw new Error('role type error! ');
    }

    / / or: role = role | | 'javascript'

    const ROLES_SAY_HELLO = ['javascript'.'go'.'python'.'java'];

    if (ROLES_SAY_HELLO.includes(role)) {
        console.log('Hello World ~'); }}Copy the code

The advantage of default parameters is that we can intuitively know the types and default Settings of the parameters, without worrying about invalid types such as undefined interfering with the logic.

6. Use of the ObjectHashMapInstead ofif-else / switch-case

function sayWords (role = 'javascript') {

    if (role === 'javascript') {
        return ['vue'.'react'];
    }

    if (role === 'python') {
        return ['Django'];
    }

    if (role === 'java') {
        return ['JavaWeb'.'Spring'];
    }

    return [];
}
Copy the code

or

function sayWords (role = 'javascript') {

    switch (role) {
        case 'javascript':
            return ['vue'.'react'];
        
        case 'python':
            return ['Django'];
        
        case 'java':
            return ['JavaWeb'.'Spring'];
        
        default:
            return[]; }}Copy the code

We can write things like this without if-else, a literal object can do it.

function sayWords (role = 'javascript') {

    const LANG_STACK = {
        javascript: ['vue'.'react'.'angular'].python: ['Django'].java: ['JavaWeb'.'Spring']}return LANG_STACK[role] || [];
}
Copy the code

By maintaining all branch information with Object, we eliminate the arcane if-else, and the logic is more centralized. Of course, we also encounter another slightly more complicated case, such as:

function sayWords (role = 'javascript', name = 'css') {

    if (role === 'javascript') {

        /** ** ** /
        let availableNames = getNamesByRole(role);

        if (availableNames.includes(name)) {
            return ['vue'.'react'];
        }
        return [];
    }

    if (role === 'python') {

        /** ** ** /
        let isAvailable = checkRoleName(role, name);

        if (isAvailable) {
            return ['Django'];
        } 
        return [name];
    }

    if (role === 'java') {

        /** ** ** /
        let availableNames = getNamesByRole(role);

        if (availableNames.includes(name)) {
            return ['JavaWeb'.'Spring'];
        }
        return[role]; }}Copy the code

For example, as the logic branch increases, the whole function becomes very large and heavy, and the nesting level becomes more and more. At this time, we need to think about how to optimize this piece of logic. First of all, if the scene is appropriate, we can still choose to use Object literal objects for logical convergence. The difference is that we extract each small piece of logic as a function for separate maintenance.

Examples of improvements:

function sayWords (role = 'javascript', name = 'css') {

    const LANG_STACK = {
        javascript: jsHandle(role, name),
        python: pythonHandle(role, name),
        java: javaHandle(role, name)
    }

    return LANG_STACK[role];
}

/** * javascript language processor * @method jsHandle * @param {String} role * @param {String} name ** @returns {Array} */
function jsHandle (role, name) {
    let availableNames = getNamesByRole(role);

    if (availableNames.includes(name)) {
        return ['vue'.'react'];
    }
    return [];
}

/** * Python language processor * @method pythonHandle * @param {String} role * @param {String} name ** @returns {Array} */
function pythonHandle (role, name) {
    let isAvailable = checkRoleName(role, name);

    if (isAvailable) {
        return ['Django'];
    } 
    return [name];
}

/** * Java language processor * @method javaHandle * @param {String} role * @param {String} name ** @returns {Array} */
function javaHandle (role, name) {
    let availableNames = getNamesByRole(role);

    if (availableNames.includes(name)) {
        return ['JavaWeb'.'Spring'];
    }
    return [role];
}
Copy the code

Obviously, when the main logic is broken down, it’s pretty neat. We use the policy mode to do the corresponding differential encapsulation processing for each case and extract the smallest unit. Even if we add more cases later, we only need to add a handler function and configure the object information in the main logic without adding if-else.

conclusion

Recently I read part of the code of the old project, and saw many different conditional branch processing methods. I am sensitive to branch, so I will temporarily comb and record it. Of course, the process of multi-person collaboration is inevitable, each person has a different approach, in a sense, there is no right or wrong, but some situations can be better.

Method not only these, these are our normal development encoding process may be more common writing and improvement ways, or specific, we need to think more in real scene, flexible, hope everyone take a few minutes of “thinking” coding process, take a few minutes of “obsessive-compulsive disorder”, constantly searching for the optimal method and write more nice code.

Finally, welcome to correct the wrong!