分享5个小技巧让你写出更好的 JavaScript 条件语句


Posted in Javascript onOctober 20, 2018

在使用 JavaScript 时,我们常常要写不少的条件语句。这里有五个小技巧,可以让你写出更干净、漂亮的条件语句。

1. 使用 Array.includes 来处理多重条件

举个栗子 :

// 条件语句
function test(fruit) {
 if (fruit == 'apple' || fruit == 'strawberry') {
  console.log('red');
 }
}

乍一看,这么写似乎没什么大问题。然而,如果我们想要匹配更多的红色水果呢,比方说『樱桃』和『蔓越莓』?我们是不是得用更多的 || 来扩展这条语句?

我们可以使用 Array.includes(Array.includes) 重写以上条件句。

function test(fruit) {

 // 把条件提取到数组中
 const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

 if (redFruits.includes(fruit)) {
  console.log('red');
 }
}

我们把红色的水果(条件)都提取到一个数组中,这使得我们的代码看起来更加整洁。

2. 少写嵌套,尽早返回

让我们为之前的例子添加两个条件:

如果没有提供水果,抛出错误。

如果该水果的数量大于 10,将其打印出来。

function test(fruit, quantity) {
 const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

 // 条件 1:fruit 必须有值
 if (fruit) {
  // 条件 2:必须为红色
  if (redFruits.includes(fruit)) {
   console.log('red');

   // 条件 3:必须是大量存在
   if (quantity > 10) {
    console.log('big quantity');
   }
  }
 } else {
  throw new Error('No fruit!');
 }
}

// 测试结果
test(null); // 报错:No fruits
test('apple'); // 打印:red
test('apple', 20); // 打印:red,big quantity

让我们来仔细看看上面的代码,我们有:

1 个 if/else 语句来筛选无效的条件
3 层 if 语句嵌套(条件 1,2 & 3)

就我个人而言,我遵循的一个总的规则是当发现无效条件时尽早返回。
/_ 当发现无效条件时尽早返回 _/

function test(fruit, quantity) {
 const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

 // 条件 1:尽早抛出错误
 if (!fruit) throw new Error('No fruit!');

 // 条件2:必须为红色
 if (redFruits.includes(fruit)) {
  console.log('red');

  // 条件 3:必须是大量存在
  if (quantity > 10) {
   console.log('big quantity');
  }
 }
}

如此一来,我们就少写了一层嵌套。这是种很好的代码风格,尤其是在 if 语句很长的时候(试想一下,你得滚动到底部才能知道那儿还有个 else 语句,是不是有点不爽)。

如果反转一下条件,我们还可以进一步地减少嵌套层级。注意观察下面的条件 2 语句,看看是如何做到这点的:
/_ 当发现无效条件时尽早返回 _/

function test(fruit, quantity) {
 const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

 if (!fruit) throw new Error('No fruit!'); // 条件 1:尽早抛出错误
 if (!redFruits.includes(fruit)) return; // 条件 2:当 fruit 不是红色的时候,直接返回

 console.log('red');

 // 条件 3:必须是大量存在
 if (quantity > 10) {
  console.log('big quantity');
 }
}

通过反转条件 2 的条件,现在我们的代码已经没有嵌套了。当我们代码的逻辑链很长,并且希望当某个条件不满足时不再执行之后流程时,这个技巧会很好用。

然而,并没有任何硬性规则要求你这么做。这取决于你自己,对你而言,这个版本的代码(没有嵌套)是否要比之前那个版本(条件 2 有嵌套)的更好、可读性更强?

是我的话,我会选择前一个版本(条件 2 有嵌套)。原因在于:

这样的代码比较简短和直白,一个嵌套的 if 使得结构更加清晰。
条件反转会导致更多的思考过程(增加认知负担)。

因此,始终追求更少的嵌套,更早地返回,但是不要过度。感兴趣的话,这里有篇关于这个问题的文章以及 StackOverflow 上的讨论:

Avoid Else, Return Early by Tim Oxley
StackOverflow discussion on if/else coding style

3. 使用函数默认参数和解构

我猜你也许很熟悉以下的代码,在 JavaScript 中我们经常需要检查 null / undefined 并赋予默认值:

function test(fruit, quantity) {
 if (!fruit) return;
 const q = quantity || 1; // 如果没有提供 quantity,默认为 1

 console.log(`We have ${q} ${fruit}!`);
}

//测试结果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

事实上,我们可以通过函数的默认参数来去掉变量 q。

function test(fruit, quantity = 1) { // 如果没有提供 quantity,默认为 1
 if (!fruit) return;
 console.log(`We have ${quantity} ${fruit}!`);
}

//测试结果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

是不是更加简单、直白了?请注意,所有的函数参数都可以有其默认值。举例来说,我们同样可以为 fruit 赋予一个默认值:function test(fruit = 'unknown', quantity = 1)。

那么如果 fruit 是一个对象(Object)呢?我们还可以使用默认参数吗?

function test(fruit) { 
 // 如果有值,则打印出来
 if (fruit && fruit.name) {
  console.log (fruit.name);
 } else {
  console.log('unknown');
 }
}

//测试结果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

观察上面的例子,当水果名称属性存在时,我们希望将其打印出来,否则打印『unknown』。我们可以通过默认参数和解构赋值的方法来避免写出 fruit && fruit.name 这种条件。

// 解构 —— 只得到 name 属性
// 默认参数为空对象 {}
function test({name} = {}) {
 console.log (name || 'unknown');
}

//测试结果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

既然我们只需要 fruit 的 name 属性,我们可以使用 {name} 来将其解构出来,之后我们就可以在代码中使用 name 变量来取代 fruit.name。

我们还使用 {} 作为其默认值。如果我们不这么做的话,在执行 test(undefined) 时,你会得到一个错误 Cannot destructure property name of 'undefined' or 'null'.,因为 undefined 上并没有 name 属性。(译者注:这里不太准确,其实因为解构只适用于对象(Object),而不是因为undefined 上并没有 name 属性(空对象上也没有)。参考解构赋值 - MDN)
如果你不介意使用第三方库的话,有一些方法可以帮助减少空值(null)检查:

使用 Lodash get 函数

使用 Facebook 开源的 idx 库(需搭配 Babeljs)

这里有一个使用 Lodash 的例子:

// 使用 lodash 库提供的 _ 方法
function test(fruit) {
 console.log(_.get(fruit, 'name', 'unknown'); // 获取属性 name 的值,如果没有,设为默认值 unknown
}

//测试结果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

你可以在这里运行演示代码。另外,如果你偏爱函数式编程(FP),你可以选择使用 Lodash fp——函数式版本的 Lodash(方法名变为 get 或 getOr)。

相较于 switch,Map / Object 也许是更好的选择

让我们看下面的例子,我们想要根据颜色打印出各种水果:

function test(color) {
 // 使用 switch case 来找到对应颜色的水果
 switch (color) {
  case 'red':
   return ['apple', 'strawberry'];
  case 'yellow':
   return ['banana', 'pineapple'];
  case 'purple':
   return ['grape', 'plum'];
  default:
   return [];
 }
}

//测试结果
test(null); // []
test('yellow'); // ['banana', 'pineapple']

上面的代码看上去并没有错,但是就我个人而言,它看上去很冗长。同样的结果可以通过对象字面量来实现,语法也更加简洁:

// 使用对象字面量来找到对应颜色的水果
 const fruitColor = {
  red: ['apple', 'strawberry'],
  yellow: ['banana', 'pineapple'],
  purple: ['grape', 'plum']
 };

function test(color) {
 return fruitColor[color] || [];
}

或者,你也可以使用 Map 来实现同样的效果:

// 使用 Map 来找到对应颜色的水果
 const fruitColor = new Map()
  .set('red', ['apple', 'strawberry'])
  .set('yellow', ['banana', 'pineapple'])
  .set('purple', ['grape', 'plum']);

function test(color) {
 return fruitColor.get(color) || [];
}

Map 是 ES2015 引入的新的对象类型,允许你存放键值对。

那是不是说我们应该禁止使用 switch 语句? 别把自己限制住。我自己会在任何可能的时候使用对象字面量,但是这并不是说我就不用 switch,这得视场景而定。
Todd Motto 有一篇文章深入讨论了 switch 语句和对象字面量,你也许会想看看。

懒人版:重构语法

就以上的例子,事实上我们可以通过重构我们的代码,使用 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 test(color) {
 // 使用 Array filter 来找到对应颜色的水果

 return fruits.filter(f => f.color == color);
}

解决问题的方法永远不只一种。对于这个例子我们展示了四种实现方法。Coding is fun!

5. 使用 Array.every 和 Array.some 来处理全部/部分满足条件

最后一个小技巧更多地是关于使用新的(也不是很新了)JavaScript 数组函数来减少代码行数。观察以下的代码,我们想要检查是否所有的水果都是红色的:

const fruits = [
  { name: 'apple', color: 'red' },
  { name: 'banana', color: 'yellow' },
  { name: 'grape', color: 'purple' }
 ];

function test() {
 let isAllRed = true;

 // 条件:所有的水果都必须是红色
 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() {
 // 条件:(简短形式)所有的水果都必须是红色
 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() {
 // 条件:至少一个水果是红色的
 const isAnyRed = fruits.some(f => f.color == 'red');

 console.log(isAnyRed); // true
}

总结

以上所述是小编给大家介绍的分享5个小技巧让你写出更好的 JavaScript 条件语句,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
不错的一个日期输入 动态
Nov 06 Javascript
键盘控制事件应用教程大全
Nov 24 Javascript
FullCalendar日历插件应用之数据展现(一)
Dec 23 Javascript
vuejs在解析时出现闪烁的原因及防止闪烁的方法
Sep 19 Javascript
ASP.NET jquery ajax传递参数的实例
Nov 02 Javascript
浅析使用BootStrap TreeView插件实现灵活配置快递模板
Nov 28 Javascript
Webpack打包css后z-index被重新计算的解决方法
Jun 18 Javascript
JavaScript在控件上添加倒计时功能的实现代码
Jul 04 Javascript
vue文件树组件使用详解
Mar 29 Javascript
koa源码中promise的解读
Nov 13 Javascript
高性能js数组去重(12种方法,史上最全)
Dec 21 Javascript
在Vue中使用Echarts实例图的方法实例
Oct 10 Javascript
angular4 获取wifi列表中文显示乱码问题的解决
Oct 20 #Javascript
vue 项目地址去掉 #的方法
Oct 20 #Javascript
VUE-cli3使用 svg-sprite-loader
Oct 20 #Javascript
vuex2中使用mapGetters/mapActions报错的解决方法
Oct 20 #Javascript
Vue项目pdf(base64)转图片遇到的问题及解决方法
Oct 19 #Javascript
使用pkg打包Node.js应用的方法步骤
Oct 19 #Javascript
简化版的vue-router实现思路详解
Oct 19 #Javascript
You might like
利用PHP制作简单的内容采集器的原理分析
2008/10/01 PHP
Zend Framework教程之Autoloading用法详解
2016/03/08 PHP
谈谈php对接芝麻信用踩的坑
2016/12/01 PHP
PHP实现图片防盗链破解操作示例【解决图片防盗链问题/反向代理】
2020/05/29 PHP
js实现拖拽 闭包函数详细介绍
2012/11/25 Javascript
javascript实现颜色渐变的方法
2013/10/30 Javascript
javascript中怎么做对象的类型判断
2013/11/11 Javascript
jqeury-easyui-layout问题解决方法
2014/03/24 Javascript
自制的文件上传JS控件可支持IE、chrome、firefox etc
2014/04/18 Javascript
浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序
2017/02/19 Javascript
JS实现课堂随机点名和顺序点名
2017/03/09 Javascript
温故知新——JavaScript中的字符串连接问题最全总结(推荐)
2017/08/21 Javascript
把vue-router和express项目部署到服务器的方法
2018/02/21 Javascript
javascript与PHP动态往类中添加方法对比
2018/03/21 Javascript
webpack4 + react 搭建多页面应用示例
2018/08/03 Javascript
浅谈HTTP 缓存的那些事儿
2018/10/17 Javascript
JS Generator 函数的含义与用法实例总结
2020/04/08 Javascript
解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题
2020/07/27 Javascript
初步探究Python程序的执行原理
2015/04/11 Python
Python的string模块中的Template类字符串模板用法
2016/06/27 Python
Python3中条件控制、循环与函数的简易教程
2017/11/21 Python
python3.6 实现AES加密的示例(pyCryptodome)
2018/01/10 Python
对numpy中轴与维度的理解
2018/04/18 Python
解决pandas中读取中文名称的csv文件报错的问题
2018/07/04 Python
Python virtualenv虚拟环境实现过程解析
2020/04/18 Python
jupyter使用自动补全和切换默认浏览器的方法
2020/11/18 Python
websocket+sockjs+stompjs详解及实例代码
2018/11/30 HTML / CSS
印度尼西亚最大和最全面的网络商城:Blibli.com
2017/10/04 全球购物
Eton丹麦官网:精美的男式衬衫
2020/05/27 全球购物
什么叫应用程序域?什么是受管制的代码?什么是强类型系统?什么是装箱和拆箱?
2016/08/13 面试题
过程装备与控制工程专业个人的求职信
2013/12/01 职场文书
爱情寄语大全
2014/04/09 职场文书
基层党组织建设整改方案
2014/09/16 职场文书
培训通知书模板
2015/04/17 职场文书
早会开场白台词大全
2015/06/01 职场文书
oracle数据库去除重复数据
2022/05/20 Oracle