简化循环和逻辑
核心思想:把条件、循环以及其他对控制流的改变做得越“自然”越好。运用一种方式使读者不用停下来重读你的代码。
1、简化控制流
1.1 条件语句中参数的顺序
变量通常放在左侧,被比较的值放在右侧。
比如
if (length > 10)
就比
if (10 < length)
要好
1.2 if/else语句块顺序
通常条件语句块的顺序可以自由安排,这里有几种建议可能会让顺序变得更好:
1、首先处理正逻辑而不是负逻辑的情况。例如,用if(debug)而不是if(!debug)
2、先处理掉简单的情况。这种方式可能还会使得if和else在屏幕之内都可见
3、先处理有趣的或者是可疑的情况
有时这些建议可能有冲突,还是要根据实际情况进行选择,总得原则还是看起来易于理解就可以了。
1.3 三目运算符
很多语言支持三目运算符,类似cond?a:b这种写法,其实是if/else的另一种紧凑写法。一个建议是,如果三目运算符中的表达式比较简单易懂,可以使用,例如
就比下面写法更好
但如果表达式复杂,不再是从两个简单的变量中做出选择,那么还是使用if/else比较好。例如:
就不如下面的易懂。
1.4 避免do/while循环
do/while循环总是会执行一边,至于是否会再执行取决于后面的条件。从写法上看,条件总是放在最后,而不是放在开头,这会造成心理“包袱”,当读到循环体的时候,你会一直惦记着条件是什么,看到条件又得回过头来再看一遍。
另外do/while再配合上continue语句,会更让人疑惑,比如下面的语句,你能一下子反应过来他做了什么吗?
1.5 从函数中提前返回
从函数中提前返回有助于让代码更好理解和简单,尤其是配合if语句用于判断一些异常情况,满足了就直接返回。例如:
1.6 避免使用goto
现在流行的语言基本很少有这个语句了。
1.7 最小化嵌套
嵌套很深的代码很难以理解。每个嵌套层次都在读者的“思维栈”上增加了一个条件。当读者见到一个右大括号(})时,可能很难“出栈”来回忆起它背后的条件是什么。
有几个方法可以减少嵌套。
通过提早返回来减少嵌套
通过改变条件和提前返回达到减少嵌套的目的,经过改进,下面的代码明显好于前面的写法。
减少循环内的嵌套
提前返回return可能不一定适用在循环体中,这个时候可以使用continue达到类似的效果。比如:
通过continue和提前返回来简化,效果如下:
2、拆分超长的表达式
核心思想:把你的超长表达式拆分成更容易理解的小块。
2.1 使用解释的变量
拆分表达式最简单的方式就是给它一个变量名,用变量名代替它,这个额外的变量有时叫做“解释变量”,它可以说明表达式的含义
引入一个解释变量,可读性提升。
2.2 总结变量
即使一个表达式不需要解释(因为你可以看出它的含义),把它装入一个新变量中仍然有用。我们把它叫做总结变量,它的目的只是用一个短很多的名字来代替一大块代码,这个名字会更容易管理和思考。
我们把表达式提取出来,专门用一个变量进行表示,更容易理解。
2.3 使用德摩根定理
对于一个布尔表达式,有两种等价的写法:
试着用德摩根定理,把表达换一种写法,可能效果会更好。
转换成等价的写法,这样容易理解多了。
2.4 滥用短路逻辑
在很多编程语言中,布尔操作会做短路计算。例如,语句if(a||b)在a为真时不会计算b。使用这种行为很方便,但有时可能会被滥用以实现复杂逻辑。
上面的写法就不如下面这么下,虽然会增加代码行数,但是更便于理解。
短路逻辑并非没有用武之地,而是避免和复杂的表达式混在一起,但用在恰当的地方也是不错的选择,比如
3、 变量与可读性
本小节主要解决下面三个问题:
1.变量越多,就越难全部跟踪它们的动向。
2.变量的作用域越大,就需要跟踪它的动向越久。
3.变量改变得越频繁,就越难以跟踪它的当前值。
3.1 减少变量
前面提到增加“解释性”和“总结性”变量,这跟减少变量并不冲突,我们的目标是 减少那些不能改进可读性的变量。
没有价值的临时变量
判断是否有价值,可以参考以下几个方面:
它没有拆分任何复杂的表达式
它没有做更多的澄清
它只用过一次,因此它并没有压缩任何冗余代码
now变量在这里就显得多余
减少中间结果
使用前面提到的提前返回技巧,可以减少一些不必须要的中间变量
提前返回,这样代码就显得更简洁易懂,同时不必引入中间变量
减少控制流变量
有时候通过增加done或者flag等控制变量来控制循环,如果仅仅是控制循环,没有其他作用,其实可以通过优化代码结构来消除这样的冗余变量
done这个变量只是用于控制循环,通过改进代码结构,可以不需要引入这个多余的变量。
4、缩小变量的作用域
核心思想:让你的变量对尽量少的代码行可见。
假如有一个很大的类,有一个成员变量只有两个方法用到,如下:
某种意义上讲,成员变量就是一个“小型全局变量”,能尽量不用最好不用。找出这种非必要的成员变量,把他们降格为局部变量。
有些语言有块级作用域(比如if/while等)的概念,比如C/Java/Golang等,如果你的变量只在块级作用域中使用,比如
可以通过if中的条件进行定义
还有一种技巧是通过“闭包”来屏蔽变量,假如你有一个长期存在的变量,只有一个函数会用到它,例如:
通过“闭包”的写法,来“消除”这个变量。
最后,值得一提的是,每种语言作用域各不相同,你要熟悉每种语言的作用域。比如,JavaScript中如果没有用var/const/let定义变量,那么默认就是全局作用域;python中没有块级作用域的概念。