使用 JavaScript 编写更好的条件语句


 做者:cuppar
https://www.zcfy.cc/article/tips-to-write-better-conditionals-in-javascript-dev-community

在任何编程语言中,代码须要根据不一样的条件在给定的输入中作不一样的决定和执行相应的动做。javascript

例如,在一个游戏中,若是玩家生命点为0,游戏结束。在天气应用中,若是在早上被查看,显示一个日出图片,若是是晚上,则显示星星和月亮。在这篇文章中,咱们将探索JavaScript中所谓的条件语句如何工做。vue

若是你使用JavaScript工做,你将写不少包含条件调用的代码。条件调用可能初学很简单,可是还有比写一对对if/else更多的东西。这里有些编写更好更清晰的条件代码的有用提示。java

  1. 数组方法 Array.includes
  2. 提早退出 / 提早返回
  3. 用对象字面量或Map替代Switch语句
  4. 默认参数和解构
  5. 用 Array.every & Array.some 匹配所有/部份内容
  6. 使用可选链和空值合并

1. 数组方法 Array.includes

使用 Array.includes 进行多条件选择web

例如:编程

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

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

上面的代码看起来很好由于咱们只检查了两个动物。然而,咱们不肯定用户输入。若是咱们要检查任何其余动物呢?若是咱们经过添加更多“或”语句来扩展,代码将变得难以维护和不清晰。数组

解决方案:微信

咱们能够经过使用 Array.includes 来重写上面的条件app

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

这里,咱们建立来一个动物数组,因此条件语句能够和代码的其他部分抽象分离出来。如今,若是咱们想要检查任何其余动物,咱们只须要添加一个新的数组项。编程语言

咱们也能在这个函数做用域外部使用这个动物数组变量来在代码中的其余任意地方重用它。这是一个编写更清晰、易理解和维护的代码的方法,不是吗?编辑器

2. 提早退出 / 提早返回

这是一个精简你的代码的很是酷的技巧。我记得当我开始专业工做时,我在第一天学习使用提早退出来编写条件。

让咱们在以前的例子上添加更多的条件。用包含肯定属性的对象替代简单字符串的动物。

如今的需求是:

  • 若是没有动物,抛出一个异常
  • 打印动物类型
  • 打印动物名字
  • 打印动物性别
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'

你以为上面的代码怎么样?

它工做得很好,可是代码很长而且维护困难。若是不使用lint工具,找出闭合花括号在哪都会浪费不少时间。😄 想象若是代码有更复杂的逻辑会怎么样?大量的if..else语句。

咱们能用三元运算符、&&条件等语法重构上面的功能,但让咱们用多个返回语句编写更清晰的代码。

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'

在这个重构过的版本中,也包含了解构和默认参数。默认参数确保若是咱们传递undefined做为一个方法的参数,咱们仍然有值能够解构,在这里它是一个空对象{}。

一般,在专业领域,代码被写在这两种方法之间。

另外一个例子:

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'

如今,咱们有:

  • 1 if/else 语句过滤非法条件
  • 3 级嵌套if语句 (条件 1, 2, & 3)

一个广泛遵循的规则是:在非法条件匹配时提早退出。

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');
      }
   }
}

经过这么作,咱们少了一个嵌套层级。当你有一个长的if语句时,这种代码风格特别好。

咱们能经过条件倒置和提早返回,进一步减小嵌套的if语句。查看下面的条件2,观察咱们是怎么作的

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');
  }
}

经过倒置条件2,代码没有嵌套语句了。这种技术在咱们有不少条件而且当任何特定条件不匹配时,咱们想中止进一步处理的时候特别有用。

因此,老是关注更少的嵌套和提早返回,但也不要过分地使用。

3. 用对象字面量或Map替代Switch语句

让咱们来看看下面的例子,咱们想要基于颜色打印水果:

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']

上面的代码没有错误,可是它仍然有些冗长。相同的功能能用对象字面量以更清晰的语法实现:

// 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] || [];
}

另外,你也能用 Map 来实现相同的功能:

// 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 容许保存键值对,是自从ES2015以来可使用的对象类型。

对于上面的例子,相同的功能也能用数组方法Array.filter 来实现。

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);
}

4. 默认参数和解构

当使用 JavaScript 工做时,咱们老是须要检查 null/undefined 值并赋默认值,不然可能编译失败。

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!

若是 vegetable 是一个对象呢?咱们能赋一个默认参数吗?

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

printVegetableName(undefined); // unknown
printVegetableName({}); // unknown
printVegetableName({ name'cabbage'quantity2 }); // cabbage

在上面的例子中,若是vegetable 存在,咱们想要打印 vegetable name, 不然打印"unknown"。

咱们能经过使用默认参数和解构来避免条件语句 if (vegetable && vegetable.name) {} 。

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

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


printVegetableName(undefined); // unknown
printVegetableName({ }); // unknown
printVegetableName({ name'cabbage'quantity2 }); // cabbage

由于咱们只须要 name 属性,因此咱们可使用 { name } 解构参数,而后咱们就能在代码中使用 name 做为变量,而不是 vegetable.name

咱们还赋了一个空对象 {} 做为默认值,由于当执行 printVegetableName(undefined) 时会获得一个错误:不能从 undefinednull 解构属性 name ,由于在 undefined 中没有 name 属性。

5. 用 Array.every & Array.some 匹配所有/部份内容

咱们能使用数组方法减小代码行。查看下面的代码,咱们想要检查是否全部的水果都是红色的:

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
}

这代码太长了!咱们能用 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
}

类似地,若是咱们想测试是否有任何红色的水果,咱们能用一行 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
}

6. 使用可选链和空值合并

这有两个为编写更清晰的条件语句而即将成为 JavaScript 加强的功能。当写这篇文章时,它们尚未被彻底支持,你须要使用 Babel 来编译。

可选链容许咱们没有明确检查中间节点是否存在地处理 tree-like 结构,空值合并和可选链组合起来工做得很好,以确保为不存在的值赋一个默认值。

这有一个例子:

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

因此,若是咱们想要打印是否车辆生产商来自美国,代码将看起来像这样:

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


checkCarManufacturerState() // 'true'

你能清晰地看到当有一个更复杂的对象结构时,这能变得多乱。有一些第三方的库有它们本身的函数,像 lodash 或 idx。例如 lodash 有 _.get 方法。然而,JavaScript 语言自己被引入这个特性是很是酷的。

这展现了这些新特性如何工做:

// 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');
   }
}

这看起来很美观并容易维护。它已经到 TC39 stage 3 阶段,让咱们等待它得到批准,而后咱们就能无处不在地看到这难以置信的语法的使用。

总结

让咱们为了编写更清晰、易维护的代码,学习并尝试新的技巧和技术,由于在几个月后,长长的条件看起来像搬石头砸本身的脚。😄


近期
Vue超好玩的新特性:在CSS中使用JS变量
完全理解 Cookie、Session、Token、JWT

若此文有用,何不素质三连❤️

本文分享自微信公众号 - Vue中文社区(vue_fe)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索