如何利用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 相关文章推荐
表单内同名元素的控制
Nov 22 Javascript
Jquery 动态添加按钮实现代码
May 06 Javascript
JavaScript高级程序设计 扩展--关于动态原型
Nov 09 Javascript
javascript中input中readonly和disabled区别介绍
Oct 23 Javascript
Jquery EasyUI的添加,修改,删除,查询等基本操作介绍
Oct 11 Javascript
浅析JavaScript中的typeof运算符
Nov 30 Javascript
JavaScript知识点总结(六)之JavaScript判断变量数据类型
May 31 Javascript
js在ie下打开对话窗口的方法小结
Oct 24 Javascript
浅谈KOA2 Restful方式路由初探
Mar 14 Javascript
vue实现分环境打包步骤(给不同的环境配置相对应的打包命令)
Jun 04 Javascript
JavaScript this在函数中的指向及实例详解
Oct 14 Javascript
swiper自定义分页器的样式
Sep 14 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
ThinkPHP模板判断输出Present标签用法详解
2014/06/30 PHP
php自动获取关键字的方法
2015/01/06 PHP
Laravel实现定时任务的示例代码
2017/08/10 PHP
Laravel多域名下字段验证的方法
2019/04/04 PHP
php常用字符串长度函数strlen()与mb_strlen()用法实例分析
2019/06/25 PHP
JQuery 获得绝对,相对位置的坐标方法
2010/02/09 Javascript
jQuery弹出层始终垂直居中相对于屏幕或当前窗口
2013/04/01 Javascript
jquery+json实现数据列表分页示例代码
2013/11/15 Javascript
js实现鼠标经过时图片滚动停止的方法
2015/02/16 Javascript
使用JS实现图片展示瀑布流效果的实例代码
2016/09/12 Javascript
javascript 动态脚本添加的简单方法
2016/10/11 Javascript
值得分享的JavaScript实现图片轮播组件
2016/11/21 Javascript
详解axios在vue中的简单配置与使用
2017/05/10 Javascript
详解ES6通过WeakMap解决内存泄漏问题
2018/03/09 Javascript
Vue实现根据hash高亮选项卡
2019/05/27 Javascript
Layer组件多个iframe弹出层打开与关闭及参数传递的方法
2019/09/25 Javascript
详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法
2020/04/07 Javascript
vue scroll滚动判断的实现(是否滚动到底部、滚动方向、滚动节流、获取滚动区域dom元素)
2020/06/11 Javascript
vue实现公告栏文字上下滚动效果的示例代码
2020/06/16 Javascript
微信小程序实现加入购物车滑动轨迹
2020/11/18 Javascript
学习python处理python编码问题
2011/03/13 Python
python中的turtle库函数简单使用教程
2018/07/23 Python
解决python3 Pycharm上连接数据库时报错的问题
2018/12/03 Python
OpenCV 边缘检测
2019/07/10 Python
Python如何使用OS模块调用cmd
2020/02/27 Python
Softmax函数原理及Python实现过程解析
2020/05/22 Python
纯html5+css3下拉导航菜单实现代码
2013/03/18 HTML / CSS
具有防紫外线功能的高性能钓鱼服装:Hook&Tackle
2018/08/16 全球购物
英国家居用品和床上用品零售商:P&B Home
2020/01/16 全球购物
荷兰时尚精品店:Labels Fashion
2020/03/22 全球购物
自考生毕业自我鉴定
2013/10/10 职场文书
思想汇报范文
2013/11/04 职场文书
税务会计岗位职责
2014/02/18 职场文书
教师思想作风整顿个人剖析材料
2014/10/10 职场文书
防暑降温通知书
2015/04/27 职场文书
Java Socket实现多人聊天系统
2021/07/15 Java/Android