1
summary: let us look at the following common condition expression scenarios, how to write beautifully!

Share this article from Huawei cloud community " how to write beautiful conditional expression - JavaScript achieve articles ", the original author: Charles.

Conditional expression is a problem that we can never avoid in the coding process, and it is also the most convenient thing for us to deceive the number of lines of code (dog head.jpg), but as a programmer, we also have to pursue our own "sindya ", let's take a look at the following common conditional expression scenarios, how to write beautifully!

  • Multiple conditional statements
  • Multi-attribute object
  • Replace the switch statement
  • Default parameters and deconstruction
  • Match all or part of the conditions
  • Use optional chain and Nullish merge

Multiple conditional statements

Use Array.includes for multiple conditional statements

for example

function printAnimals(animal) {
  if (animal === "dog" || animal === "cat") {
    console.log(`I have a ${animal}`);
  }
}

console.log(printAnimals("dog")); // I have a dog

This way of writing seems to be no problem when there are fewer conditions. At this time, we only have 2 kinds of animals, but what if we have more conditions to judge (more animals)? If we continue to expand the conditions of judgment, the code will become difficult to maintain and the logic will be unclear.

Solution

You can use Array.includes to rewrite conditional statements

function printAnimals(animal) {
  const animals = ["dog", "cat", "hamster", "turtle"];

  if (animals.includes(animal)) {
    console.log(`I have a ${animal}`);
  }
}

console.log(printAnimals("hamster")); // I have a hamster

Here, we created an array of animals in order to extract the conditions separately from the rest of the code. Now, if we want to check any other animals, all we need to do is add a new array item.

We can also use the animals variable outside the scope of this function to reuse it in other places in the code. This is a way to write code that is clearer, easier to understand and maintain. Isn't it?

Multi-attribute object

This is a very good technique to compress your code and make it look more concise. Let's take the previous example as an example and add more conditions. What if the animal is not a simple string, but an object with certain properties?

So the requirements now are:

  • If there are no animals, throw an error
  • Print the type of animal
  • Print the name of the animal
  • Print the sex of the animal
const printAnimalDetails = (animal) => {
  let result; // declare a variable to store the final value

  // condition 1: check if animal has a value
  if (animal) {
    // condition 2: check if animal has a type property
    if (animal.type) {
      // condition 3: check if animal has a name property
      if (animal.name) {
        // condition 4: check if animal has a gender property
        if (animal.gender) {
          result = `${animal.name} is a ${animal.gender} ${animal.type};`;
        } else {
          result = "No animal gender";
        }
      } else {
        result = "No animal name";
      }
    } else {
      result = "No animal type";
    }
  } else {
    result = "No animal";
  }

  return result;
};

console.log(printAnimalDetails()); // 'No animal'

console.log(printAnimalDetails({ type: "dog", gender: "female" })); // 'No animal name'

console.log(printAnimalDetails({ type: "dog", name: "Lucy" })); // 'No animal gender'

console.log(
  printAnimalDetails({ type: "dog", name: "Lucy", gender: "female" })
); // 'Lucy is a female dog'

The above code works very well, but the code is very long and difficult to maintain. If you don't use the hint tool, you may waste some time to determine the position of the closing parenthesis. Imagine what will happen if the code is more complex logic. A lot of if...else statements!

We can use ternary operators, && conditions, etc. to refactor the above functions, but let us use multiple return statements to write more precise code.

const printAnimalDetails = ({ type, name, gender } = {}) => {
  if (!type) return "No animal type";
  if (!name) return "No animal name";
  if (!gender) return "No animal gender";

  // Now in this line of code, we're sure that we have an animal with all //the three properties here.

  return `${name} is a ${gender} ${type}`;
};

console.log(printAnimalDetails()); // 'No animal type'

console.log(printAnimalDetails({ type: dog })); // 'No animal name'

console.log(printAnimalDetails({ type: dog, gender: female })); // 'No animal name'

console.log(printAnimalDetails({ type: dog, name: "Lucy", gender: "female" })); // 'Lucy is a female dog'

In the refactored version, deconstruction and default parameters are also included. The default parameters ensure that if we pass undefined as a parameter to the method, we still have a value to deconstruct, here is an empty object {}.

Usually, the code is written between these two methods.

for example

function printVegetablesWithQuantity(vegetable, quantity) {
  const vegetables = ["potato", "cabbage", "cauliflower", "asparagus"];

  // condition 1: vegetable should be present
  if (vegetable) {
    // condition 2: must be one of the item from the list
    if (vegetables.includes(vegetable)) {
      console.log(`I like ${vegetable}`);

      // condition 3: must be large quantity
      if (quantity >= 10) {
        console.log("I have bought a large quantity");
      }
    }
  } else {
    throw new Error("No vegetable from the list!");
  }
}

printVegetablesWithQuantity(null); //  No vegetable from the list!
printVegetablesWithQuantity("cabbage"); // I like cabbage
printVegetablesWithQuantity("cabbage", 20);
// 'I like cabbage`
// 'I have bought a large quantity'

Now, we have:

  • Filter if/else statements for invalid conditions
  • 3 levels of nested if statements (condition 1, 2 and 3)
  • A general rule is to return as soon as possible when an invalid condition is found.

A general rule is to return as soon as possible when an invalid condition is found

function printVegetablesWithQuantity(vegetable, quantity) {
  const vegetables = ["potato", "cabbage", "cauliflower", "asparagus"];

  // condition 1: throw error early
  if (!vegetable) throw new Error("No vegetable from the list!");

  // condition 2: must be in the list
  if (vegetables.includes(vegetable)) {
    console.log(`I like ${vegetable}`);

    // condition 3: must be a large quantity
    if (quantity >= 10) {
      console.log("I have bought a large quantity");
    }
  }
}

By doing this, we reduce the level of a nested statement. This coding style is good, especially when using long if statements. By reversing the condition and returning early, we can further reduce the nested if.

Please see how condition 2 is done below:

function printVegetablesWithQuantity(vegetable, quantity) {
  const vegetables = ["potato", "cabbage", "cauliflower", "asparagus"];

  if (!vegetable) throw new Error("No vegetable from the list!");
  // condition 1: throw error early

  if (!vegetables.includes(vegetable)) return;
  // condition 2: return from the function is the vegetable is not in
  //  the list

  console.log(`I like ${vegetable}`);

  // condition 3: must be a large quantity
  if (quantity >= 10) {
    console.log("I have bought a large quantity");
  }
}

By reversing the condition of condition 2, the code no longer has nested statements. This technique is useful when we have many conditions and want to stop further processing when any particular condition is not met.

Therefore, always aim to reduce nesting and return as soon as possible, but don't overdo it.

Replace the switch statement

Let's take a look at the following example, we want to print fruits according to color:

function printFruits(color) {
  // use switch case to find fruits by color
  switch (color) {
    case "red":
      return ["apple", "strawberry"];
    case "yellow":
      return ["banana", "pineapple"];
    case "purple":
      return ["grape", "plum"];
    default:
      return [];
  }
}

printFruits(null); // []
printFruits("yellow"); // ['banana', 'pineapple']

There is no error in the implementation of the above code, but it is very verbose. The same result can be achieved using a more concise syntax.

// use object literal to find fruits by color
const fruitColor = {
  red: ["apple", "strawberry"],
  yellow: ["banana", "pineapple"],
  purple: ["grape", "plum"],
};

function printFruits(color) {
  return fruitColor[color] || [];
}

Similarly, you can also use Map to achieve:

// use Map to find fruits by color
const fruitColor = new Map()
  .set("red", ["apple", "strawberry"])
  .set("yellow", ["banana", "pineapple"])
  .set("purple", ["grape", "plum"]);

function printFruits(color) {
  return fruitColor.get(color) || [];
}

Map is an object type available since ES5, which allows key-value storage.

For the example above, you can use Array.filter to achieve the same result.

const fruits = [
  { name: "apple", color: "red" },
  { name: "strawberry", color: "red" },
  { name: "banana", color: "yellow" },
  { name: "pineapple", color: "yellow" },
  { name: "grape", color: "purple" },
  { name: "plum", color: "purple" },
];

function printFruits(color) {
  return fruits.filter((fruit) => fruit.color === color);
}

Default parameters and deconstruction

When using JavaScript, we always need to check for null/undefined and assign default values or break the compilation.

function printVegetablesWithQuantity(vegetable, quantity = 1) {
// if quantity has no value, assign 1

  if (!vegetable) return;
    console.log(`We have ${quantity} ${vegetable}!`);
  }
  //results
}

printVegetablesWithQuantity('cabbage'); // We have 1 cabbage!
printVegetablesWithQuantity('potato', 2); // We have 2 potato!

What if the vegetable is an object? Can we assign a default parameter?

function printVegetableName(vegetable) {
  if (vegetable && vegetable.name) {
    console.log(vegetable.name);
  } else {
    console.log("unknown");
  }
}

printVegetableName(undefined); // unknown
printVegetableName({}); // unknown
printVegetableName({ name: "cabbage", quantity: 2 }); // cabbage

In the above example, we want to print the vegetable name (if it is available) or print unknown.

We can avoid the condition if (vegetable && vegetable.name){} by using default parameters & destructuring.

// destructing - get name property only
// assign default empty object {}

function printVegetableName({ name } = {}) {
  console.log(name || "unknown");
}

printVegetableName(undefined); // unknown
printVegetableName({}); // unknown
printVegetableName({ name: "cabbage", quantity: 2 }); // cabbage

Because we only need the attribute name, we can use {name} to change the structure of the parameter, and then we can use name as a variable in the code instead of vegetable.name.

We will also assign an empty object {} as the default value, otherwise when executing printVegetableName(undefined), it will give an error-Cannot destructure property name of undefined or null, because there is no name property in undefined.

Match all or part of the conditions

We can reduce the number of lines of code by using these Array methods.

In the following code, we want to check whether all fruits are red:

const fruits = [
  { name: "apple", color: "red" },
  { name: "banana", color: "yellow" },
  { name: "grape", color: "purple" },
];

function test() {
  let isAllRed = true;

  // condition: all fruits must be red
  for (let f of fruits) {
    if (!isAllRed) break;
    isAllRed = f.color == "red";
  }

  console.log(isAllRed); // false
}

The above code is too verbose, we can reduce the lines of code by using Array.every:

const fruits = [
  { name: "apple", color: "red" },
  { name: "banana", color: "yellow" },
  { name: "grape", color: "purple" },
];

function test() {
  // condition: short way, all fruits must be red
  const isAllRed = fruits.every((f) => f.color == "red");

  console.log(isAllRed); // false
}

Similarly, if we want to test whether any fruit is red, we can use Array.some:

const fruits = [
  { name: "apple", color: "red" },
  { name: "banana", color: "yellow" },
  { name: "grape", color: "purple" },
];

function test() {
  // condition: if any fruit is red
  const isAnyRed = fruits.some((f) => f.color == "red");

  console.log(isAnyRed); // true
}

Use optional chain and Nullish merge

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/%E5%8F%AF%E9%80%89%E9%93%BE

These two functions are very useful for writing more concise conditions in JavaScript. At the time of writing, they are not fully supported and may need to be compiled with Babel.

Optional links can handle a tree-like structure without the need to explicitly check whether intermediate nodes exist, and Nullish combined with optional links is very effective to ensure that there is no default value for the node.

for example:

const car = {
  model: "Fiesta",
  manufacturer: {
    name: "Ford",
    address: {
      street: "Some Street Name",
      number: "5555",
      state: "USA",
    },
  },
};

// to get the car model
const model = (car && car.model) || "default model";

// to get the manufacturer street
const street =
  (car &&
    car.manufacturer &&
    car.manufacturer.address &&
    car.manufacturer.address.street) ||
  "default street";

// request an un-existing property
const phoneNumber =
  car &&
  car.manufacturer &&
  car.manufacturer.address &&
  car.manufacturer.phoneNumber;

console.log(model); // 'Fiesta'
console.log(street); // 'Some Street Name'
console.log(phoneNumber); // undefined

Therefore, if we want to print it out, if the car manufacturer is from the United States, the code should look like this:

const isManufacturerFromUSA = () => {
  if (
    car &&
    car.manufacturer &&
    car.manufacturer.address &&
    car.manufacturer.address.state === "USA"
  ) {
    console.log("true");
  }
};

checkCarManufacturerState(); // 'true'
You can clearly see how confusing this can become for more complex object structures. There are some third-party libraries, such as lodash or idx, which have their own functions. For example, lodash has a _.get method. However, this feature is introduced in the JavaScript language itself.

Here is how these new features work:

// to get the car model
const model = car?.model ?? "default model";

// to get the manufacturer street
const street = car?.manufacturer?.address?.street ?? "default street";

// to check if the car manufacturer is from the USA
const isManufacturerFromUSA = () => {
  if (car?.manufacturer?.address?.state === "USA") {
    console.log("true");
  }
};

Currently in Stage 3 stage.

The above is some sharing of conditional expressions based on JavaScript, I hope it can be helpful to you~

Click to follow, and get to know the fresh technology of


华为云开发者联盟
1.4k 声望1.8k 粉丝

生于云,长于云,让开发者成为决定性力量