Summarizes Ways to Write Better Code

助教统整 n 个方法帮助你写出更好的代码

前言

本篇文章主要是经验的浓缩,如果要详细的撰写建议可以参考看看:无瑕的程序代码 JavaScript🔗,里面有更全面的说明与案例。

方法一:良好的命名

刚学习程序的时候太常会一头栽入逻辑、语法或框架中,而忽略最简单且重要的事情:「良好的命名」。在批改了无数种类的作业之后发现这是最常发生也是最 容易 (困难) 被解决的问题。 良好的命名可以真正的帮助提升任何种类代码的质量,帮助你自己与他人更好的了解程序的脉络,它甚至与写程序无关!所以任何人应当都能够理解这个概念。

那么「良好的命名」普遍具备那些条件?

明确且简单

命名应当明确且简白描述该命名事物的内容,举例来说声明一个用户名的变量,内容是什么就描述清楚,不要含糊也不要赘述

// a 是什么意思? (无意义)
const a = 'Joe';
// 暂时的数据? (统称)
const usernameTemp = 'Joe';
// 它当然是一笔资料 (赘述)
const TheUsername = 'Joe';
const usernameData = 'Joe';
const usernameValue = 'Joe';
const usernameInfo = 'Joe';
const usernameContent = 'Joe';
// 什么都没描述清楚 (统称+赘述)
const apiUrl = 'www.example.com/api';
const dataStore = 'Joe';
const str = 'Joe';
// 更 OK 的命名方式
const username = 'Joe'; // 用户名称,清楚
const attractionUrl = 'www.example.com/api'; // 景点网址,清楚
// 获取……什么资料?
function getData() {
// ...
}
// 获取用户资料,OK
function getUser() {
// ...
}
// 获取远端用户资料,OK
function fetchUser() {
// ...
}
const locations = ['Austin', 'New York', 'San Francisco'];
// l 是什么意思?
locations.forEach((l) => {
dispatch(l);
});
// 其中的地点,OK
locations.forEach((location) => {
dispatch(location);
});

简单来说,如果命名只是一些填充用的字,并没有什么实际的意义,就应该在命名中避免!虽然上面的例子看起来理所当然,但说不定在压力与时间的挤压或无意识中真的会写出这样的命名。写小程序还好,但规模只要一扩大就会变成一场灾难,千万不能有“只是在练习,先写再改的侥幸心态”,那么这个诅咒将会一直困扰你与阅读你代码的人 👻

避免缩写

使用缩写会让程序变得更加难以理解,虽然当下看起来简洁好懂但也应当极力避免。举例来说你正在制作一个游戏的血量机制:Health Point (HP),这样命名很常见也很合理,但不常打游戏的人可能会清楚这是什么意思,或者之后出现了 Hit PointHigh PointHighest Point? 命名上就出现了冲突。因此除了常见的专有名词像是:HTMLXMLAPI 还能接受外,能不用缩写就不要使用缩写。

避免神奇数字

神奇数字是指在程序中让人无法理解其用途的数字,举例来说:

function isPasswordValid(password) {
if (password.length < 5) {
return false;
}
if (password.length > 16) {
return false;
}
return true;
}

为了让程序更好被理解、查询与修改,不应该散落“神奇数字”在程序之中,把它们声明为一个变量并且取个好名字通常来说会是更好的做法:

function isPasswordValid(password) {
const passwordMinLength = 5;
const passwordMaxLength = 16;
if (password.length < passwordMinLength) {
return false;
}
if (password.length > passwordMaxLength) {
return false;
}
return true;
}

如果有“未来可能改动”或是“单看数字很难理解用途”的情况,就应该把它们声明为一个变量并且给它一个好名称。

避免使用 var

var 是一个早期变量声明方式,简单来说它会让你的变量变成全局变量,这样会让程序变得难以维护,因此应当避免使用 var。事实是:你只会越来越少见 var,请视情况使用 constlet

使用命名惯例

不同的程序语言社区有不同的命名惯例🔗,常见你会看到:

  • CamelCase (大驼峰)
  • camelCase (小驼峰)
  • kebab-case (烤肉串)
  • snake_case (蛇型)

等等很多其他类型的缩写……这些命名惯例都是为了让程序更一致而存在的规范,举例来说:JavaScript 通常会使用 camelCase,而 CSS 或 HTML 通常会使用 kebab-case。 就算没有参与多人开发的环境,也迟早要阅读他人的代码,所以尽早养成该语言普遍在用的命名惯例是越早越好。

除了会用之外还要一致,如果一个程序里面包含了多种撰写规范会导致难以维护,是应当极力避免的

方法二:避免注释

如果依循严格的命名与规范,程序代码通常就足够清楚到不需要注释了,过多的注释绝对会影响到程序的可读性! 对我来说注释适合用来描述更高层级的概念,例如:为什么要这样架构程序?而不是程序实现上的细节描述。甚至注释是不需要的,因为更高层级的概念可以被在文档当中描述。

这个部分比较倾向偏好了,我相信好的程序代码就是最好的注释,如果你也觉得这样比较好,那么就尽量避免使用注释吧!

方法三:不要重复造轮子

每当在写程序时,我们无时无刻都可以站在他人的肩膀上,只要你懂得怎么运用,使用现有的解决方案是最节省时间精力的事,也可以让代码更简洁易于维护。常见的问题通常早就已经有他人深思熟虑过的最优解,像是操纵数据强烈建议可以补齐 操纵数组的方法🔗 。 (这里预计会再写一篇专门的文章讲解 😉)

除了把重点真正放在如何解决问题而不是如何实现之外,也可以让你的代码更容易被其他人理解。

方法三:使用最合适的资料型态

在 JavaScript 中,有很多资料型态可以使用,像是 stringnumberbooleanarrayobjectnullundefined等等,每个资料型态都有自己的特性,使用最合适的资料型态可以让代码更简洁易读,也可以避免一些不必要的错误。

举例来说使用 string 来储存一个数字,可能会导致一些不必要的错误,例如:'1' + '1' 会变成 '11' 而不是 2,这样的错误很难被发现;或是使用 string 来储存一个开关的状态,这样的代码会让人很难理解,因为 string 通常会让人联想到储存字符串而不是是或否的结果。

挑选正确的资料型态可以让代码更简洁易读,也可以避免一些不必要的错误。

方法四:去除冗余的逻辑

举一个计算是否输入的值为奇数的程序,与其判断结果并返回 truefalse,直接返回结果就好了:

// ❌ 冗余的逻辑
function isOdd(number) {
if (number % 2 === 1) {
return true;
} else {
return false;
}
}
// ✅ OK
const isOdd = (num) => {
return num % 2 === 1;
};

有的冗余逻辑则是因为创造“自己才明白的抽象”才导致的,可以参考看看以下示例,其中将“被选取”的项目用“自定义状态码”来呈现,这样的抽象做只会单纯的损害代码的可读性,并没有任何实质的帮助 😅:

// ❌ 冗余的逻辑
const selected = 0;
if (selected === 0) {
showVegetable();
} else if (selected === 1) {
showFruit();
} else if (selected === 2) {
showFlower();
}
// ✅ OK
const selected = 'flower';
if (selected === 'vegetable') {
showVegetable();
} else if (selected === 'fruit') {
showFruit();
} else if (selected === 'flower') {
showFlower();
}

甚至与其去判断,不如把对象作为一个查找表,这样的写法会更简洁容易更改,易读的话就看人了:

// 😎 OK
const productTable = {
vegetable: showVegetable,
fruit: showFruit,
flower: showFlower,
};
if (isSelected) {
productTable[selected]();
}
function showVegetable() {}
function showFruit() {}
function showFlower() {}

或是你也可以把三个 show某某 的函数用一个 show 函数来取代并传入参数,不过还是要看代码前后脉络,这里就不深入讨论了。

参考资料