如何利用JavaScript编写更好的条件语句详解


Posted in Javascript onAugust 10, 2020

前言

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

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

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

1. 数组方法 Array.includes

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

例如:

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

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

上面的代码看起来很好因为我们只检查了两个动物。然而,我们不确定用户输入。如果我们要检查任何其他动物呢?如果我们通过添加更多“或”语句来扩展,代码将变得难以维护和不清晰。

解决方案:

我们可以通过使用 Array.includes 来重写上面的条件

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.filte 来实现。

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', quantity: 2 }); // 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', quantity: 2 }); // cabbage

因为我们只需要 name 属性,所以我们可以使用 { name } 解构参数,然后我们就能在代码中使用 name 作为变量,而不是 vegetable.name。

我们还赋了一个空对象 {} 作为默认值,因为当执行 printVegetableName(undefined) 时会得到一个错误:不能从 undefined 或 null 解构属性 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 阶段,让我们等待它获得批准,然后我们就能无处不在地看到这难以置信的语法的使用。

总结

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

到此这篇关于如何利用JavaScript编写更好的条件语句的文章就介绍到这了,更多相关JavaScript条件语句内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
复制Input内容的js代码_支持所有浏览器,修正了Firefox3.5以上的问题
Jun 21 Javascript
jQuery EasyUI API 中文文档 - Spinner微调器使用
Oct 21 Javascript
JavaScript插件化开发教程 (四)
Jan 27 Javascript
jQuery插件slider实现拖动滑块选取价格范围
Apr 30 Javascript
Vue组件BootPage实现简单的分页功能
Sep 12 Javascript
js实现将json数组显示前台table中
Jan 10 Javascript
Bootstrap下拉菜单更改为悬停(hover)触发的方法
May 24 Javascript
基于ExtJs在页面上window再调用Window的事件处理方法
Jul 26 Javascript
angular2 ng2 @input和@output理解及示例
Oct 10 Javascript
Validform验证时可以为空否则按照指定格式验证
Oct 20 Javascript
解决angularjs WdatePicker ng-model的问题
Sep 13 Javascript
Vue项目打包编译优化方案
Sep 16 Javascript
vue-cli单页面预渲染seo-prerender-spa-plugin操作
Aug 10 #Javascript
js实现计算器功能
Aug 10 #Javascript
js实现盒子拖拽动画效果
Aug 09 #Javascript
js实现盒子移动动画效果
Aug 09 #Javascript
js实现弹窗效果
Aug 09 #Javascript
js实现表格数据搜索
Aug 09 #Javascript
js实现微信聊天界面
Aug 09 #Javascript
You might like
解析PHP中的内存管理,PHP动态分配和释放内存
2013/06/28 PHP
php提取身份证号码中的生日日期以及验证是否为成年人的函数
2015/09/29 PHP
php的PDO事务处理机制实例分析
2017/02/16 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
2017/11/17 PHP
Yii框架ACF(accessController)简单权限控制操作示例
2019/04/26 PHP
实现变速回到顶部的JavaScript代码
2011/05/09 Javascript
Js动态添加复选框Checkbox的实例方法
2013/04/08 Javascript
js实现按Ctrl+Enter发送效果
2014/09/18 Javascript
js倒计时小实例(多次定时)
2016/12/08 Javascript
ajax实现加载页面、删除、查看详细信息 bootstrap美化页面!
2017/03/14 Javascript
使用Node搭建reactSSR服务端渲染架构
2018/08/30 Javascript
js获取对象,数组所有属性键值(key)和对应值(value)的方法示例
2019/06/19 Javascript
vue实现弹幕功能
2019/10/25 Javascript
Vue实现导航栏的显示开关控制
2019/11/01 Javascript
关于JavaScript中异步/等待的用法与理解
2020/11/18 Javascript
[02:05]2014DOTA2西雅图邀请赛 专访啸天mik夫妻档
2014/07/08 DOTA
[03:21]【TI9纪实】Old Boys
2019/08/23 DOTA
Python类的专用方法实例分析
2015/01/09 Python
python列表操作实例
2015/01/14 Python
Python导出DBF文件到Excel的方法
2015/07/25 Python
对Python3中的input函数详解
2018/04/22 Python
使用Django简单编写一个XSS平台的方法步骤
2019/03/25 Python
python程序控制NAO机器人行走
2019/04/29 Python
详解Python中的format格式化函数的使用方法
2019/11/20 Python
Python中用xlwt制作表格实例讲解
2020/11/05 Python
CSS3中引入多种自定义字体font-face
2020/06/12 HTML / CSS
英国最大的宠物食品和宠物用品网上零售商: Zooplus
2016/08/01 全球购物
ECCO爱步加拿大官网:北欧丹麦鞋履及皮具品牌
2017/07/08 全球购物
中国跨镜手机配件批发在线商店:TVC-Mall
2019/08/20 全球购物
乌克兰在线药房:Аптека24
2019/10/30 全球购物
热能动力工程毕业生自荐信
2013/11/07 职场文书
办公自动化毕业生求职信
2014/03/09 职场文书
五月的鲜花活动方案
2014/08/21 职场文书
财务会计实训报告
2014/11/05 职场文书
公司岗位说明书
2015/10/08 职场文书
用Python将GIF动图分解成多张静态图片
2021/06/11 Python