变量名的力量
有意义的变量名
选择好的名字需要花费时间,但节省的钱却比花费的多。
揭示意图的名称
名称应该能够解答所有重要的问题。它应该能够告诉你它存在的原因、它的功能以及如何使用。如果名称需要注释,则说明它并没有揭示其意图。
let d; // elapsed time in days
我们应该选择能够指定测量内容和测量单位的名称:
let elapsedTimeInDays;
let daysSinceCreation;
let daysSinceModification;
let fileAgeInDays;
由于使用不当名称而难以理解的代码示例:
function getThem() {
let list1 = [];
for (let x in theList)
if (x[0] == 4) list1.add(x);
return list1;
}
问题不在于代码的简洁性,而在于代码的隐晦性。代码没有说明 in 是什么类型theList
,以及 的值是什么4
。只需给出概念名称,我们就可以显著改进代码:
function getFlaggedCells() {
let flaggedCells = [];
for (let cell in gameBoard) {
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
}
return flaggedCells;
}
或者以功能性的方式:
function getFlaggedCells(gameBoard) {
return gameBoard.filter(cell => cell[STATUS_VALUE] === FLAGGED)
}
好的和坏的变量名示例
变量的用途 | 好名字 | 坏名字 |
---|---|---|
迄今为止签发支票的累计总数 | runningTotal ,checkTotal |
written ,,,,,,,ct checks CHKTTL x x1 x2 |
子弹的速度 | velocity ,,trainVelocity velocityMph |
velt ,,,,,,,v tv train x x1 x2 |
当前日期 | currentDate ,todaysDate |
cd ,,,,,,,current c x x1 x2 date |
每页行数 | linesPerPage |
lpp ,,,,,,lines l x x1 x2 |
最佳名称长度
太长了 | 太短了 | 正好 |
---|---|---|
numberOfPeopleOnTheUsOlympicTeam |
n ,,np ntm |
numTeamMembers ,teamMemberCount |
numberOfSeatsInTheStadium |
n ,,ns nsisd |
numSeatsInStadium ,seatCount |
maximumNumberOfPointsInModernOlympics |
m ,,,mp max points |
maxTeamPoints ,maxPoints |
有意义的区别
因为你不能用同一个名字在同一作用域内指代两个不同的事物,所以你可能会忍不住随意更改一个名字。即使编译器或解释器已经满足要求,仅仅添加数字序列或干扰词(冗余)也是不够的。
function copyChars(a1, a2) {
for (let i = 0; i < a1.length; i++) {
a2[i] = a1[i];
}
}
如果名称必须不同,那么它们的含义也应该不同。数字序列{a1, a2, ... aN}
与有意命名相反。这样的名称并非虚假信息——而是非信息性名称;它们无法提供任何线索来了解作者的意图。请考虑:
function copyChars(source, target) {
for (let i = 0; i < source.length; i++) {
target[i] = source[i];
}
}
准确使用反义词。使用反义词的命名约定有助于保持一致性,从而提高可读性。
变量名中的常见反义词
- 开始/结束
- 第一个/最后一个
- 锁定/解锁
- 最小/最大
- 下一个/上一个
- 旧/新
- 打开/关闭
- 可见/不可见
- 源/目标
- 上/下
可发音的名字
如果你连一个词都念不出来,你就没法讨论它,否则听起来就像个傻瓜。这很重要,因为编程是一项社交活动。比较一下:
// ymdhms (date, year, month, day, hour)
let genymdhms;
let modymdhms;
let pszqint = "102";
到
let generationTimestamp;
let modificationTimestamp;
let recordId = "102";
可搜索名称
单字母名称和数字常量有一个特殊的问题,那就是它们在整段文本中不易定位。单字母名称只能用作短方法中的局部变量。名称的长度应与其作用域的大小相对应。如果一个变量或常量可能在代码中的多个位置出现或使用,则必须为其指定一个易于搜索的名称。请比较:
for (let j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
到
let realDaysPerIdealDay = 4;
const WORK_DAYS_PER_WEEK = 5;
let sum = 0;
for (let j = 0; j < NUMBER_OF_TASK; j++) {
let realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
let realTaskWeeks = realTaskDays / WORK_DAYS_PER_WEEK;
sum += realTaskWeeks;
}
命名特定类型的数据
命名循环索引
名称i
、j
和k
是惯常的简单循环变量名称:
for (let i = firstItem; i < lastItem; i++) {
data[i] = 0;
}
如果要在循环外使用变量,则应为其指定一个比i
、j
、更有意义的名称k
。例如,如果您正在从文件中读取记录,并且需要记住已读取的记录数,recordCount
则可以使用类似以下更有意义的名称:
let recordCount = 0
while (moreScore()) {
score[recordCount] = getNextScore();
recordCount++;
}
循环增长的一个常见原因是嵌套。如果有多个嵌套循环,请为顶部的变量分配更长的名称,以提高可读性。
for (teamIndex = 0; teamIndex < teamCount; teamIndex++) {
for (eventIndex = 0; eventIndex < eventCount[teamIndex]; eventIndex++) {
score[teamIndex][eventIndex] = 0;
}
}
精心选择循环索引变量的名称可以避免常见的索引串扰问题。避免此类问题最简单的方法就是想出比i
、j
、更具描述性的名称k
。score[teamIndex][eventIndex]
比 更具信息量score[i][j]
状态变量的命名
状态变量描述程序的状态。最好将标志视为状态变量。标志应该被赋值,并且应该使用枚举类型、命名常量或充当命名常量的全局变量来测试其值。以下是一些名称不当的标志示例:
if (flag) ...
if (statusFlag == 0x0F) ...
if (printFlag == 16) ...
if (computeFlag == 0) ...
flag = 0x1;
statusFlag = 0x80;
printFlag = 16
computeFlag = 0;
以下是更清晰的等效代码示例:
if (dataReady) ...
if (charType & PRINTABLE_CHAR) ...
if (reportType == reportTypeEnum.annual) ...
if (recalcNeeded == true) ...
dataReady = true;
charType = CONTROL_CHARACTER;
reportType = reportTypeEnum.annual
recalcNeeded = false;
命名临时变量
临时变量用于保存计算的中间结果、作为临时占位符以及保存常规值。它们通常被称为temp
、x
或其他一些模糊且不具描述性的名称。通常,临时变量表明程序员尚未完全理解问题。此外,由于这些变量已被正式赋予了temporary
地位,程序员对待它们往往比其他变量更随意,从而增加了出错的可能性。
let temp = Math.sqrt(b^2 - 4*a*c);
root[0] = (-b + temp) / (2 * a);
root[1] = (-b - temp) / (2 * a);
变量名temp
并不能告诉你它的具体用途。以下示例展示了一种更好的方法:
let disciminant = Math.sqrt(b^2 - 4*a*c);
root[0] = (-b + disciminant) / (2 * a);
root[1] = (-b - disciminant) / (2 * a);
命名布尔变量
有用的布尔变量名:
- 完毕
- 错误
- 成立
- 成功
为布尔变量命名,暗示true
或false
done
像和 这样的名称success
是好的布尔名称,因为状态是true
或。另一方面,像和 这样false
的名称则是差的布尔名称,因为它们显然不是或。status
sourceFile
true
false
为了获得更好的结果,请用类似或 的status
名称替换,并用或或变量所代表的任何内容替换。error
statusOK
sourceFile
sourceFileAvailable
sourceFileFound
有些程序员喜欢Is
在布尔值前面加上 。这样变量名就变成了问题:?????isDone
用或来回答问题isError
,就会得到变量的值。isFound
isProcessingComplete
true
false
使用正布尔变量名
notFound
诸如、notDone
和之类的否定名称notSuccessful
在被否定时很难阅读。
命名枚举类型
const daysEnum = Object.freeze({
monday: 0,
tuesday: 1,
wednesday: 2,
thursday: 3,
friday: 4,
saturday: 5,
sunday: 6
});
更进一步,可以将逻辑提取到一个具有可变参数数量的函数中,并生成一个冻结对象。这种技术几乎没有什么好处,所以更好的选择是创建一个简单的类。毕竟,枚举在面向对象编程语言中更为常见,所以这听起来很合适。
命名常量
命名常量时,应使用常量所代表的抽象实体来命名,而不是使用常量所引用的数字。FIVE
是一个糟糕的常量名称。FIVE = 6
会很荒谬。CYCLES_NEEDED
是一个好名称。同样,BAKERS_DOZEN
也是一个糟糕的常量名称;DONUT_MAX
是一个好的常量名称。
使用变量的常见问题
虚假信息
程序员必须避免留下虚假的线索,以免混淆代码的含义。我们应该避免使用那些根深蒂固的含义与预期含义不同的词语。缩写可能会误导信息。
不要将账户分组称为 ,accountList
除非它本身就是List
。“列表”一词对程序员来说有特定的含义。如果存放账户的容器不是List
,则可能会导致错误的结论。“所以”accountGroup
或“直接”accounts
会更好。
一个真正糟糕的虚假命名示例是将大小写字母L
混合用作O
变量名,尤其是大小写字母的组合。当然,问题在于它们看起来几乎完全像常量 1 和 0。
let a = l;
if (O == l) a = O1;
else l = 01;
问题导向
一个好的名称助记符通常能够表达问题本身,而不是解决方案。一个好的名称更应该关注“是什么” ,而不是“如何” 。一般来说,如果一个名称指的是计算的某个方面,而不是问题本身,那么它应该关注“如何”而不是“是什么”。避免使用这样的名称,而应该使用能够直接指向问题本身的名称。
员工数据记录可以称为inputRec
或employeeData
。inputRec
是一个计算机术语,指的是计算概念——输入和记录。employeeData
指的是问题域,而不是计算领域。同样,对于指示打印机状态的位字段,bitFlag
比 更像计算机名称printerReady
。在会计应用中,calcVal
更像计算机名称。
编码
我们已经有足够的编码需要处理,无需再增加负担。将类型或范围信息编码到名称中只会增加额外的解读负担。这在解决问题时会造成不必要的精神负担。编码名称很少能发音,而且很容易输入错误。编码系统会误导读者。
建议
- 避免使用误导性的名称或缩写
- 避免使用含义相似的名字
- 避免使用含义不同但名称相似的变量
- 避免在名称中使用数字
- 避免姓名拼写错误
- 不要仅通过大写字母来区分变量名称
- 避免使用多种自然语言
- 避免使用标准类型、变量和例程的名称
- 不要使用与变量含义无关的名称
- 避免使用难以阅读的字符的名称
命名约定
为什么要举行大会?
- 它们让你把更多事情视为理所当然。通过做出一个全局决策而不是多个局部决策,你可以专注于代码中更重要的特性。
- 它们帮助你跨项目传递知识。相似的名称能让你更轻松、更自信地理解不熟悉的变量应该做什么。
- 它们可以帮助您在新项目中更快地学习编码。
- 它们减少了名称的泛滥。如果没有命名约定,你很容易用两个不同的名称来称呼同一个事物。例如,你可能会把总分称为
pointTotal
和totalPoints
。 - 它们弥补了语言的弱点。该约定可以区分本地数据、类数据和全局数据。
- 它们强调相关项目之间的关系。
何时应该有命名约定?
- 当多个程序员在一个项目上工作时
- 当你计划将程序交给另一个程序员进行修改和维护时
- 当你的程序被组织内的其他程序员审查时
- 当你的程序太大,你无法一次性记住整个程序,而必须分段思考时
- 当你的程序寿命足够长时,你可能会把它放在一边几周或几个月,然后再重新开始
- 当你在项目中有很多不常见的术语,并且想要在编码中使用标准术语或缩写时
某种命名约定总是有益的。上述考虑应该能帮助你确定该约定在特定项目中的适用范围。
命名变量时最重要的考虑因素是名称要完整准确地描述变量所代表的实体。
好的变量名是程序可读性的关键要素。
参考书目:
- Martin, RC (2009). 代码整洁之道:敏捷软件工艺手册。培生教育出版社。
- McConnell, S. (2004). 代码完整。培生教育。
感谢 Julien Dephix、Ben Sinclair 和其他帮助改进本文的顾问。
文章来源:https://dev.to/adillaumam/the-power-of-variable-names-2cm4