yinguangyao / blog

关于 JavaScript 前端开发、工作经验的一点点总结。

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

万事开头难 —— 如何起一个好的变量名?

yinguangyao opened this issue · comments

commented

前言

名字是一个人在社会中必不可少的符号与标识,也是信息表达、交流、传播的一种工具。每当提起一个人的名字,我们总是能联想到对应的人,这就是名字的作用。

相信每个人都应该看过小说吧。在小说中,重要人物名都是很有讲究的。尤其是在好的小说中,往往从一个人的名字就能联想到此人的性格和命运。

例如:李寻欢,表面有寻欢作乐之意,而他也的确是个放浪不羁又多情的剑客;『君子剑』岳不群,孔子曰:君子矜而不争,群而不党。不群不群,暗示他是个伪君子。

let 李寻欢; // 想必此人是个浪子
let 岳不群; // 很明显是个伪君子
let 张三; // 为什么叫张三?长了三只眼?三只手?家里排行老三?

我扯了这么多小说中的人物名,这和我们今天的主题是不是有关系呢?没错,如果在程序中能起一个好的变量名,对于可维护性和可读性都会有很大的提升。

命名规范

由于JS中没有强制规定变量命名规范,因此出现了很多命名规范,比如:匈牙利命名法(数据类型+描述)、大驼峰命名法(FirstName)、小驼峰命名法(firstName)、下划线命名法(first_name)。

在这篇文章中,我们统一规定一下对类和构造函数应当使用大驼峰命名法,对其他的变量和函数都使用小驼峰命名法。

let FirstName; // bad
let first_name; // bad
let first-name; // bad
let firstName; // good

避免抽象词

在为变量命名时,要尽量避免抽象的变量名。
例如下面这段代码,一眼看上去就摸不着头脑。 xyxx 是什么?谁能知道这段代码是计算净收入的呢?

// 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之前,如果我们想要避免全局变量的污染,只能将变量挂载到一个对象中,将这个对象暴露到全局中。这样做的好处就是将多个全局变量按功能进行了划分,不管是可读性还是扩展性上都有不错的表现。

例如:在全局中有 findremove 两个方法,我们可能不知道这是干什么的。但是在我们常用的 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
}

循环中的变量名

我们应该都很喜欢在 forforEach 等循环中用 ijk 等来命名下标吧,如果只有一层循环,这样的确没什么问题,言简意赅。
可如果有两层以上的循环,再使用 ijk 就很容易造成困惑了,毕竟 ijk 都是下标值,一不小心就搞混淆了。

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++) {
        // 虽然变量名长了点,但这样就会更容易让人理解
        }
    }
}

总结

学习变量命名最好的方法就是看社区内知名框架和库的源码(点名批评一波React源码中变量名又臭又长),参考别人在多人协作的大项目中是怎么命名的。随着自己编程经验越来越丰富,对变量命名就会驾轻就熟。

最后,我总结了一下文章中所讲的一些知识点。

  1. 类名和构造函数名首字母应当大写。
  2. 类或对象的私有属性,应该以 _ 开头。
  3. 变量命名应该避免抽象词,用更专业、准确的词来代替。
  4. 变量名中可以包含更多的信息,比如编码、单位等等。
  5. 变量名不宜过长,不超过三个单词。
  6. 在不同的作用域层级中,变量名应该有所调整。
  7. 善用 begin/endfirst/lastmin/max 等对仗词。
  8. 在多重循环中,应该用更加具体的变量名来代替 ijk 等等。