The translation

Conditionals are often used when writing JavaScript code. Here are five tips to help you write better, more concise conditionals.

1. Use array. includes to process various conditions

Let’s look at an example:

// conditionfunction test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}}
Copy the code

At first glance, the above example seems fine. But what if we added more red fruits, like cherries and cranberries? That is about to use | | write more condition judgment. To solve this problem, we can use array.includes to override the above criteria. Here’s an example:

function test(fruit) {
// extract conditions to array
const redFruits = ['apple'.'strawberry'.'cherry'.'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}}
Copy the code

Extract the “red fruit” (condition) into the array, so it looks neat.

2. Reduce nesting and return early

Let’s expand on the previous example by adding two conditions:

  • Throw an exception if there is no fruit
  • If the quantity exceeds 10, the quantity of fruit is exported
function test(fruit, quantity) {
  const redFruits = ['apple'.'strawberry'.'cherry'.'cranberries'];
  // condition 1: fruit must has value
  if (fruit) {
    // condition 2: must be red
    if (redFruits.includes(fruit)) {
      console.log('red');
      // condition 3: must be big quantity
      if (quantity > 10) {
        console.log('big quantity'); }}}else {
    throw new Error('No fruit! '); / /}}test results
test(null); // error: No fruits
test('apple'); // print: red
test('apple', 20); // print: red, big quantity
Copy the code

Looking at the code above, you see the following problems:

  • An if/else statement that filters out invalid conditions
  • One general rule I personally follow is to return as early as possible when dealing with invalid conditions
/ _return early when invalid conditions found _/
function test(fruit, quantity) {
  const redFruits = ['apple'.'strawberry'.'cherry'.'cranberries'];
  // condition 1: throw error early
  if(! fruit) throw new Error('No fruit! ');
  // condition 2: must be red
  if (redFruits.includes(fruit)) {
    console.log('red');
    // condition 3: must be big quantity
    if (quantity > 10) {
      console.log('big quantity'); }}}Copy the code

By writing this way, you can reduce the nesting by one level. This is good when the if statement is long. (Imagine if you had to scroll very far down to see the else language, which would not be cool). We can also reduce the nesting of if statements by using the reverse condition and returning early, as shown in the second condition.

/ _return early when invalid conditions found _/

function test(fruit, quantity) {
  const redFruits = ['apple'.'strawberry'.'cherry'.'cranberries'];
  if(! fruit) throw new Error('No fruit! '); // condition 1: throw error early
  if(! redFruits.includes(fruit))return; // condition 2: stop when fruit is not red
  console.log('red');
  // condition 3: must be big quantity
  if (quantity > 10) {
    console.log('big quantity'); }}Copy the code

By taking the opposite condition in the second condition, the code now releases a nest. This works well when we have to write long logic and want to stop the process further. However, this writing is not hard and fast, it depends on the specific scene. Sometimes, you have to ask yourself whether this way of writing (no nesting) is better or more readable than the previous one (nesting in condition 2).

For me, I’m just going to stay away from the previous way of writing (nested in condition 2) for two reasons:

  • This is shorter and more concise than nested if statements
  • Inverted conditional judgments may lead to more thought processes (increased cognitive load)

Therefore, always aim to reduce nesting and return early in time, but don’t overdo it. If you’re interested, check out the following related article and more discussion on this topic in StackOverflow:

  • Avoid else, return early
  • StackOverflow discussion of if/else code styles

3. Use function default arguments and destruct

I’m guessing the following code looks familiar to you, but we still need to check for null values (undefined or null) when executing JavaScript.

function test(fruit, quantity) {
  if(! fruit)return;
  const q = quantity || 1; // if quantity not provided, default to one
  console.log(`We have ${q} ${fruit}! `); } / /test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
Copy the code

In fact, we can assign default parameters to the function by eliminating the variable p. Here’s an example:

function test(fruit, quantity = 1) { // if quantity not provided, default to one
  if(! fruit)return;
  console.log(`We have ${quantity} ${fruit}! `); } / /test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
Copy the code

Doesn’t that look simple and intuitive? Remember that each argument has its own default function argument. For example, we can also assign a default value for fruit (the first argument in the above code) :

function test(fruit = 'unknown', quantity = 1)
Copy the code

Another question arises: What if the Fruit parameter is of type Object? Can we specify a default value?

function test(fruit) { 
  // printing fruit name if value provided
  if (fruit && fruit.name)  {
    console.log (fruit.name);
  } else {
    console.log('unknown'); / /}}test results
test(undefined); // unknown
test({}); // unknowntest({ name: 'apple', color: 'red' }); // apple
Copy the code

Looking at the example above, we want to print out the name of fruit if the value exists, otherwise print out “unknown”. We can avoid the fruit&& Fruit.name condition by checking the default function arguments and object destructuring. Take a look at these examples:

// destructing - get name property only
// assign default empty object {}
function test({name} = {}) {
  console.log (name || 'unknown'); } / /test results
test(undefined); // unknown
test({}); // unknowntest({ name: 'apple', color: 'red' }); // apple
Copy the code

Since we only need the fruit object’s name property, we can use {name} to deconstruct the object, and then we can use name as a variable in our code instead of Fruit.name. We will also allocate an empty object {} as the default argument. If you don’t do this, you will get an error when executing the test(undefined) line: the ‘undefined’ or ‘null’ attribute name cannot be resolved because undefined has no name attribute. If you don’t mind using third-party libraries, there are several ways to reduce null checking.

  • Use the Lodash get method
  • Use Facebook’s open source IDX library (and Bablejs)

Here’s an example of using Lodash:

// Include lodash library, you will get _
function test(fruit) {
  console.log(__.get(fruit, 'name'.'unknown'); // get property name, if not available, assign default value 'unknown'} / /test results
test(undefined); // unknown
test({}); // unknowntest({ name: 'apple', color: 'red' }); // apple
Copy the code

You can run the demo here. Alternatively, if you are keen on using functional programming (FP), you may choose to use Lodash FP, a functional version of Lodash (with the method changed to get or getOr).

4. Support Map or object literals instead of switch declarations

Let’s look at the following example:

function test(color) {
  // use switch case to find fruits in color
  switch (color) {
    case 'red':
      return ['apple'.'strawberry'];
    case 'yellow':
      return ['banana'.'pineapple'];
    case 'purple':
      return ['grape'.'plum'];
    default:
      return[]; / /}}test results
test(null); / / []test('yellow'); / / /'banana'.'pineapple']
Copy the code

The above code looks error-free, but I find it quite cluttered. You can achieve the same result with the cleaner syntax of literal objects. Such as:

// use object literal to find fruits in color
  const fruitColor = {
    red: ['apple'.'strawberry'],
    yellow: ['banana'.'pineapple'],
    purple: ['grape'.'plum']};function test(color) {
  return fruitColor[color] || [];
}
Copy the code

Alternatively, you can use a Map to achieve the same result, for example:

// use Map to find fruits in color
  const fruitColor = new Map()
    .set('red'['apple'.'strawberry'])
    .set('yellow'['banana'.'pineapple'])
    .set('purple'['grape'.'plum']);
function test(color) {
  return fruitColor.get(color) || [];
}
Copy the code

Map is an object type that has only been available since ES6 and can be used to store key-value pairs.

Use array. every and array. some for all or some rules

The final tip is about taking advantage of the new (actually not so new) JavaScript array methods to reduce code functions. Looking at the code below, we want to see if 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
}
Copy the code

The code above is really lengthy! We can use array. every to reduce the number of lines of code. Take a look at:

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
}
Copy the code

Isn’t it much simpler now? Similarly, if you want to test for red fruit, use array. some in a single line of code.

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
}
Copy the code

conclusion

Let’s work together to generate more readable code. I hope you learned something new in this article. That’s all. Happy coding! (after)

Afterword.

The above translation is only used for learning communication, the level is limited, there are inevitably mistakes, please correct me.

Read more

Deconstruct the assignment Map

The original link

The original