@gyyin
2019-05-06T00:34:19.000000Z
字数 3468
阅读 398
慕课专栏
名字是一个人在社会中必不可少的符号与标识,也是信息表达、交流、传播的一种工具。每当提起一个人的名字,我们总是能联想到对应的人,这就是名字的作用。
相信每个人都应该看过小说吧。在小说中,重要人物名都是很有讲究的。尤其是在好的小说中,往往从一个人的名字就能联想到此人的性格和命运。
例如:李寻欢,表面有寻欢作乐之意,而他也的确是个放浪不羁又多情的剑客;『君子剑』岳不群,孔子曰:君子矜而不争,群而不党。不群不群,暗示他是个伪君子。
let 李寻欢; // 想必此人是个浪子
let 岳不群; // 很明显是个伪君子
let 张三; // 为什么叫张三?长了三只眼?三只手?家里排行老三?
我扯了这么多小说中的人物名,这和我们今天的主题是不是有关系呢?没错,如果在程序中能起一个好的变量名,对于可维护性和可读性都会有很大的提升。
由于JS没有强制规定变量命名规范,因此有很多命名规范,比如:匈牙利命名法(数据类型+描述)、大驼峰命名法(FirstName)、小驼峰命名法(firstName)、下划线命名法(first_name)。
在这篇文章中,我们统一规定一下对类和构造函数应当使用大驼峰命名法,对其他的变量和函数都使用小驼峰命名法。
let FirstName; // bad
let first_name; // bad
let first-name; // bad
let firstName; // good
在为变量命名时,要尽量避免抽象的变量名。
例如下面这段代码,一眼看上去就摸不着头脑。 x
、y
、xx
是什么?谁能知道这段代码是计算净收入的呢?
// bad
let x = averIncome * months;
let y = averExpense * months;
let xx = x - y;
好的变量名应当易记、能够准确地表达出变量的意义,通常对变量的描述就是最好的变量名。
// good
let incomeTotal = averIncome * months;
let expenseTotal = averExpense * months;
let incomeNet = incomeTotal - expenseTotal;
变量命名应该以问题为导向,变量名反映的应该是问题,而不是结果。
比如我们计算某几个月的总收入,那么 total
就比 result
更好。
function calcSalary(averSalary, months) {
let result = averSalary * months; // bad
let total = averSalary * months; // good
}
在确定了变量的大致意思后,应当结合语义选择更专业、准确的词,我们可以给名字附带更多的信息。比如下面这个 get
用的就很不好。
function getPageData() {} // bad
function fetchPageData() {} // good
get
表达了什么意思呢?是从本地缓存取数据还是从网络中请求数据呢?这就是表达意思含糊不清,应当使用更准确的 fetch
来代替。
再比如这里有个保存颜色的变量,如果能加上对应的格式,那就更容易理解了。
let color = "#FFB6C1"; // bad
let hexColor = "#FFB6C1"; // good
let rgbColor = "255, 182, 193"; // good
假设有一个将字符串转换为数字类型的函数,也许你会命名为 convertStringToNumber
,这个名字的确是很准确的表达出了意思,但还是不够简练。
一般来说,变量名应该尽量不超过三个单词,我们可以使用一些众所周知的缩写词,例如:
单词 | 缩写 |
---|---|
document | doc |
evaluation | eval |
current | cur |
array | arr |
length | len |
string | str |
number | num |
但千万要注意,不应该使用自己创造的缩写词,免得给人造成困扰,比如:
单词 | 缩写 |
---|---|
password | pw |
comment | comt |
distribute | dist |
extract | ext |
component | cpt |
这样能在可读性和长度之间找到一个更好的平衡,比如上面的例子我们完全可以把它写成 str2Num
,更加简洁。
一个信息量丰富的变量名总是最好的吗?当然不是,变量名和作用域也是息息相关的。
我们都知道全局变量会污染全局环境,过多的全局变量经常会导致多人协作变量名冲突的问题,但泛泛的变量名也是全局变量带来的问题之一。
在ES6之前,如果我们想要避免全局变量的污染,只能将变量挂载到一个对象中,将这个对象暴露到全局中。这样做的好处就是将多个全局变量按功能进行了划分,不管是可读性还是扩展性上都有不错的表现。
例如:在全局中有 find
和 remove
两个方法,我们可能不知道这是干什么的。但是在我们常用的 jQuery
中,我们就很容易知道这是查询和删除 DOM
节点的。
// bad
let find = () => {};
let remove = () => {};
// good
$.fn.find = () => {};
$.fn.remove = () => {};
// good
(function($) {
let find = () => {};
let remove = () => {};
$.fn.find = find;
$.fn.remove = remove;
}(jQuery))
在ES6有了模块化规范之后,管理变量就更加容易了。一个文件就可以是一个模块,这个文件中定义的变量也不会污染全局。又因为模块都是定义好的,所以模块名也可以起到限制的作用,在模块中的变量我们都知道是和这个模块功能息息相关的。
就像上面说的一样,在局部作用域中,作用域已经起到了一部分描述的作用,那么变量名也可以适当的缩短一些。
比如有一个 calcSalary
的方法,在这个方法里面有一个叫 total
的变量,我们就很容易知道这个变量保存了计算的结果。
但如果在全局变量中有个 total
变量,恐怕我们就很难知道它所表达的意思了, salaryTotal
也许会更加合适,这也是为什么建议大家少用全局变量。
let total; // bad
let salaryTotal; // good
let calcSalary = () => {
let total; // good
}
我们应该都很喜欢在 for
、forEach
等循环中用 i
、j
、k
等来命名下标吧,如果只有一层循环,这样的确没什么问题,言简意赅。
可如果有两层以上的循环,再使用 i
、j
、k
就很容易造成困惑了,毕竟 i
、j
、k
都是下标值,一不小心就搞混淆了。
for (let i = 0; i < countries.length; i++) {
const provinces = countries[i].provinces;
for (let j = 0; j < provinces.length; j++) {
const cities = provinces[j].cities;
for (let k = 0; k < cities.length; k++) {
// i、j、k的意义表达不够明确,很容易造成混淆。
}
}
}
最好的方法就是在下标变量前面用限定词。
for (let countryIndex = 0; countryIndex < countries.length; countryIndex++) {
const provinces = countries[countryIndex].provinces;
for (let provinceIndex = 0; provinceIndex < provinces.length; provinceIndex++) {
const cities = provinces[provinceIndex].cities;
for (let cityIndex = 0; cityIndex < cities.length; cityIndex++) {
// 虽然变量名长了点,但这样就会更容易让人理解
}
}
}
学习变量命名最好的方法就是看社区内知名框架和库的源码,参考别人在多人协作的大项目中是怎么命名的。随着自己编程经验越来越丰富,对变量命名就会驾轻就熟。
最后,我总结了一下文章中所讲的一些知识点。
_
开头。begin/end
、first/last
、min/max
等对仗词。i
、j
、k
等等。