如何利用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 相关文章推荐
js 鼠标拖动对象 可让任何div实现拖动效果
Nov 09 Javascript
网页图片延时加载的js代码
Apr 22 Javascript
JS 对输入框进行限制(常用的都有)
Jul 30 Javascript
JS实现超过长度限制后自动跳转下一款文本框的方法
Feb 23 Javascript
通过node-mysql搭建Windows+Node.js+MySQL环境的教程
Mar 01 Javascript
微信小程序  Mustache语法详细介绍
Oct 27 Javascript
webpack多入口文件页面打包配置详解
Jan 09 Javascript
jQuery实现图片上传预览效果功能完整实例【测试可用】
May 28 jQuery
layui 优化button按钮和弹出框的方法
Aug 15 Javascript
vue实现select下拉显示隐藏功能
Sep 30 Javascript
javascript 原型与原型链的理解及实例分析
Nov 23 Javascript
Vue如何使用混合Mixins和插件开发详解
Feb 05 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
第十四节 命名空间 [14]
2006/10/09 PHP
服务器变量 $_SERVER 的深入解析
2013/07/02 PHP
10款PHP开源商城系统汇总介绍
2015/07/23 PHP
PHP互换两个变量值的方法(不用第三变量)
2016/11/14 PHP
php实现数组中出现次数超过一半的数字的统计方法
2018/10/14 PHP
Laravel获取当前请求的控制器和方法以及中间件的例子
2019/10/11 PHP
JavaScript setTimeout和setInterval的使用方法 说明
2010/03/25 Javascript
Javascript的getYear、getFullYear、getUTCFullYear异同分享
2011/11/30 Javascript
JS事件Event元素(兼容IE,Firefox,Chorme)
2012/11/01 Javascript
js用闭包遍历树状数组的方法
2014/03/19 Javascript
jQuery实现防止提交按钮被双击的方法
2015/03/24 Javascript
Bootstrap 网站实例之单页营销网站
2016/10/20 Javascript
javascript实现获取指定精度的上传文件的大小简单实例
2016/10/25 Javascript
jQuery倒计时代码(超简单)
2017/02/27 Javascript
详解Windows下安装Nodejs步骤
2017/05/18 NodeJs
浅析JS抽象工厂模式
2017/12/14 Javascript
浅谈Vue2.0父子组件间事件派发机制
2018/01/08 Javascript
详解vue 数据传递的方法
2018/04/19 Javascript
Vue移动端用淘宝弹性布局lib-flexible插件做适配的方法
2020/05/26 Javascript
Vue性能优化的方法
2020/07/30 Javascript
Vue3+elementui plus创建项目的方法
2020/12/01 Vue.js
[52:52]完美世界DOTA2联赛PWL S3 LBZS vs access 第一场 12.10
2020/12/13 DOTA
Python中的装饰器用法详解
2015/01/14 Python
python执行使用shell命令方法分享
2017/11/08 Python
Flask框架各种常见装饰器示例
2018/07/17 Python
python集合是否可变总结
2019/06/20 Python
Python 实现自动获取种子磁力链接方式
2020/01/16 Python
Python使用shutil模块实现文件拷贝
2020/07/31 Python
美国购买当代和现代家具网站:MODTEMPO
2018/07/20 全球购物
销售经理岗位职责
2014/03/16 职场文书
触电现场处置方案
2014/05/14 职场文书
副校长竞聘演讲稿
2014/09/01 职场文书
超市工作总结范文2014
2014/12/19 职场文书
党员年终个人总结
2015/02/14 职场文书
关于开学的感想
2015/08/10 职场文书
nginx请求限制配置方法
2021/07/09 Servers