代码不规范,同事两行泪

前言

前几天帮对床室友调bug,看到他代码中有这么一大段(如下),我内心是抗拒的,但是看在亲室友的份上,还是强忍下给他解决了问题,后来我反省,发现在自己写过的代码中也有一些这样的面条代码,一大串,不仅占地面积大,阅读性更是差,要想万一我的github里面的代码被看到是这样的,岂不是很丢脸,于是带着问题,开始了就“如何减少if else面条代码”这一问题的探究。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if () {
// something
} else if () {
// something
} else if () {
// something
} else if () {
// something
} else if () {
// something
} else if () {
// something
} else if () {
// something
} else {
// something
}

初步解决方案:Switch

当然,这似乎可以改善那么一点儿,但是还是不够简洁不够优雅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var b = 0;
var a = 12;
switch (true) {
case a <= 5:
b = 1;
break;
case (a >= 5 && a < 10):
b = 2;
break;
case (a >= 10 && a < 15):
b = 3;
break;
case (a >= 15 && a < 20):
b = 4;
break;
default:
b = 0;
break;
}
console.log(b);

升级解决办法:&& 与 || 的组合

这是一个用一行代码便可以解决很多条件判断的黑科技,在此之前我们需要详细了解&&与||的执行机制,我们先从最基础的判断来看:

1
2
3
4
console.log(true || false); // true
console.log(false || true); // true
console.log(true && true); // true
console.log(false && false); // false

这都不难理解,但是&&与||的威力远远不止用来判断简单的true和false,我们在看下面的示例:

先了解一个概念,以下值在JavaScript逻辑判断中都为false:

  • 0
  • ”“
  • null
  • false
  • undefined
  • NaN

|| 操作符

talk is cheap,先来看几个例子:

1
2
3
4
5
6
7
8
9
10
console.log(0 || 1); // 1
console.log(2 || 1); // 2
console.log("a" || 1); // 'a'
console.log("" || 1); // 1
console.log("" || 1 || 3); // 1(递进)
console.log("a" || 0); //'a'
console.log("" || 0); // 0
console.log("" || 0 || 3); // 3 (递进)
console.log(0 || ""); // ""
console.log(0 || "" || 1); // 1 (递进)

看到这里,或许你会疑惑,||怎么还有这种用法,又或者说,||是怎么来判断返回值呢?经过以上的几个分析,我们得到以下规律:

  1. 只要“||”前面为false,假如只有一个||操作符,不管“||”后面是true还是false,都返回“||”后面的值,如有多个,则逐步递进。

  2. 只要“||”前面为true,假如只有一个||操作符,不管“||”后面是true还是false,都返回“||”前面的值,如有多个,则逐步递进。

我称这种为短路原理: 知道了前面第一个的结果就知道后的输出,如果为第一个为:true,则取第一个的值,如果第一个为false,则取第后面的值。

&& 操作符

依旧先看例子:

1
2
3
4
5
6
7
8
9
console.log("" && 1); // ''
console.log("" && 0); // ''
console.log("a" && 1); // 1
console.log("a" && 0); // 0
console.log("a" && ""); // ''
console.log("a" && "" && 3); // '' (不递进)
console.log(0 && "a"); // 0
console.log(0 && "a" && 2); // 0 (不递进)
console.log(0 && ""); // 0

分析得知

1、只要“&&”前面是false,无论“&&”后面是true还是false,结果都将返“&&”前面的值,即false;

2、只要“&&”前面是true,无论“&&”后面是true还是false,结果都将返“&&”后面的值,并且不会向||一样递进;

具体用法

简单用法

熟知上面&&与||的基本用法后,我们来开始真正的实战,假如有这么一个需求:

变量a是不确定的,如果a没有赋值,那么a的默认值是12.

按照新手思想来,会写出以下下代码,这样写固然没有错误,但是如果变量多,那么代码中太多的if(){}显然不是那么的美观。

1
2
3
4
5
6
if (!a) {
a = 12;
}
if (a == null || a == "" || a == undefined) {
a = 12;
}

改进:

1
a = a || 12;

只需要一行代码,无需过多解释,很精辟,在实际项目中用的非常多,并且辨识度也很高,我们在看一题:

当变量a的值大于2,则给变量b赋值6,否则b为false

if else当然可以解决问题,但是用&&会更骚

1
2
3
4
5
6
7
8
var a = 3;
var b;
if (a>2) {
b = 6
} else {
b = false
}
console.log(b) // 6

改进:

1
2
3
var a = 2;
let b = a > 0 && 6;
console.log(b); // 6

很酷炫用没有,是不是发现之前写的代码都是很垃圾,但是!!!假如将 && 与 || 结合起来,那么你就可以改变世界了~

高级用法

有这么一个判断需求:

根据人的年龄处在哪个范围,输出处于那个年龄阶段,0-5(幼年),5-12(少年),12-18(青年),18-40(成年),40-60(中年),>60(老年).

emmmm,好像判断条件有点多,用if else是这样判断的,不忍直视。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var age = 22;
if (age >= 0 && age < 5) {
console.log("幼年");
} else if (age >= 5 && age < 12) {
console.log("少年");
} else if (age >= 12 && age < 18) {
console.log("青年");
} else if (age >= 18 && age < 40) {
console.log("成年");
} else if (age >= 40 && age < 60) {
console.log("中年");
} else {
console.log("老年");
}

那么用&&与||怎么解决呢,改变世界的时刻到了:

1
2
3
4
5
6
7
8
let man =
(age >= 0 && age < 5 && "幼年") ||
(age >= 5 && age < 12 && "少年") ||
(age >= 18 && age < 40 && "青年") ||
(age >= 18 && age < 40 && "成年") ||
(age >= 40 && age < 60 && "中年") ||
"老年";
console.log(man);

如果说理解了上面讲的操作法判断方法,理解这段代码也很简单,比起if else来说,真的美观多了,我们可以总结出下面这个模板,但是条件1和条件2切勿重叠,这是一个要非常注意的点。

1
((条件1) && (满足条件1后的值)) || ((条件2) && (满足条件2后的值)) || ...

总结

通过这次探索,切实的感受到了可读性高的简写会给代码质量带来很的提升,&&和||学习成本也不大,只要项目中用习惯了,便是一件一劳永逸的事情,你的小伙伴再也不会抱怨你的代码太丑,如果你小伙伴看不懂你用&&和||写的判断语句,那么欢迎你向他推荐我这篇文章~

Time is money :)