前言
今天是在公司实习的第二天,在安装好开发软件与配置好开发环境之后,就在我以为终于可以大施拳脚时,leader却给我发来一份前端指导手册,里面是一些新人需要阅读的文档。
就在我大失所望,以为又要辛(mo)苦(yu)一天时发现事情没那么简单。
之前在小公司实习以及个人进行一些项目开发时,很少会去关注到代码的质量,于是写出了很多可能自己看的懂但是却“拿不出手”的代码。而在进入这家稍微规模大一点的公司之后,我发现代码原来不仅是给自己看的,在开发的同时也要考虑到其他开发者的感受。
而这本代码简洁之道以很小的篇幅向我打开了一个新世界的大门。
代码简洁之道的核心内容可以理解为两句话:代码自我注释(注释要做到精简准确),对开发者友好(易于理解,修改和扩展)。
同时在开发过程中要站在其他开发者的角度思考三个问题
“WTF is that?”(这TM是啥?)
“WTF did you do here?”(你TM在做啥?)
“WTF is this for?”(你TM为什么这么做?)
复制代码
一下是代码简洁之道的主要内容外加一些我自己的理解
强类型检查
如果可以,请求永远先使用===而不是==
举个例子
// 如果没有妥善处理的话,可能会出现和预想不一样的结果
0 == false; // true
0 === false; // false
2 == "2"; // true
2 === "2"; // false
const value = "500";
if (value === 500) {
// 不会执行
console.log(value);
}
if (value === "500") {
// 会执行
console.log(value);
}
复制代码
==与===的区别这里简单说一下。
===先比较类型,在类型相等情况下比较值,类型和值都相等才返回true。
==先比较类型,类型不相等则先进行类型转换在比较
这里说的其实并不是很完整,==与===的具体区别以及为什么建议使用===。
变量命名
这部分是我之前一直忽略的,相信很多新人小伙伴也和我一样,变量命名不规范不简洁不能做到见名知意。
而其实变量命名尽量直观易懂,方便查找;而且其他开发者也容易理解。
不好的命名方式:
let daysSLV = 10;
let y = new Date().getFullYear();
let ok;
if (user.age > 30) {
ok = true;
}
复制代码
好的命名方式:
const MAX_AGE = 30;
let daysSinceLastVisit = 10;
let currentYear = new Date().getFullYear();
...
const isUserOlderThanAllowed = user.age > MAX_AGE;
复制代码
不要使用多余的无意义的单词来组合命名
坏的命名方式:
let nameValue;
let theProduct;
复制代码
好的命名方式:
let name;
let product;
复制代码
不要使用无意义的字符/单词来命名,增加额外的记忆负担
坏的命名方式:
users.forEach(u => {
doSomething();
doSomethingElse();
// ...
// ...
// ...
// ...
// 这里u到底指代什么?
register(u);
});
复制代码
好的命名方式:
const users = ["John", "Marco", "Peter"];
users.forEach(user => {
doSomething();
doSomethingElse();
// ...
// ...
// ...
// ...
register(user);
});
复制代码
在某些环境下,不用添加冗余的单词来组合命名。比如一个对象叫user,那么其中的一个名字的属性直接用name,不需要再使用username了。
坏的命名方式:
const user = {
userName: "John",
userSurname: "Doe",
userAge: "28"
};
...
user.userName;
复制代码
好的命名方式:
const user = {
name: "John",
surname: "Doe",
age: "28"
};
...
user.name;
复制代码
这些例子都是出自与原文章上的,而且大多通过正反对比来举例说明。
这里我给大家推荐一个变量命名自动生成网站以方便大家的开发,开发可以在此网站输入中文以得到响应的规范的英文变量。
函数
请使用完整的声明式的名字来给函数命名。比如一个函数实现了某个行为,那么函数名可以是一个动词或则一个动词加上其行为的被作用者。名字就应该表达出函数要表达的行为。
坏的命名方式:
function notif(user) {
// implementation
}
复制代码
好的命名方式:
function notifyUser(emailAddress) {
// implementation
}
复制代码
避免使用过多参数
避免使用过多参数。最好一个函数只有 2 个甚至更少的参数。参数越少,越容易做测试。
坏的使用方式:
function getUsers(fields, fromDate, toDate) {
// implementation
}
复制代码
好的使用方式:
function getUsers({ fields, fromDate, toDate }) {
// implementation
}
getUsers({
fields: ["name", "surname", "email"],
fromDate: "2019-01-01",
toDate: "2019-01-18"
});
复制代码
为函数参数设置默认值
为函数参数设置默认值,而不是在代码中通过条件判断来赋值。
坏的写法:
function createShape(type) {
const shapeType = type || "cube";
// ...
}
复制代码
好的写法:
function createShape(type = "cube") {
// ...
}
复制代码
一个函数应该只做一件事情
一个函数应该只做一件事情。避免将多个事情塞到一个函数中。
坏的写法:
function notifyUsers(users) {
users.forEach(user => {
const userRecord = database.lookup(user);
if (userRecord.isVerified()) {
notify(user);
}
});
}
复制代码
好的写法:
function notifyVerifiedUsers(users) {
users.filter(isUserVerified).forEach(notify);
}
function isUserVerified(user) {
const userRecord = database.lookup(user);
return userRecord.isVerified();
}
复制代码
使用Objecg.assign来设置默认对象值
坏的写法:
const shapeConfig = {
type: "cube",
width: 200,
height: null
};
function createShape(config) {
config.type = config.type || "cube";
config.width = config.width || 250;
config.height = config.width || 250;
}
createShape(shapeConfig);
复制代码
好的写法:
const shapeConfig = {
type: "cube",
width: 200
// Exclude the 'height' key
};
function createShape(config) {
config = Object.assign(
{
type: "cube",
width: 250,
height: 250
},
config
);
...
}
createShape(shapeConfig);
复制代码
不要使用true/false标签
不要使用 true/false 的标签(flag),因为它实际上让函数做了超出它本身的事情。**
坏的写法:
function createFile(name, isPublic) {
if (isPublic) {
fs.create(`./public/${name}`);
} else {
fs.create(name);
}
}
复制代码
好的写法:
function createFile(name) {
fs.create(name);
}
function createPublicFile(name) {
createFile(`./public/${name}`);
}
复制代码
不要污染全局
不要污染全局。如果你需要对现有的对象进行扩展,不要在对象的原型链上定义函数。请使用 ES 的类和继承。
坏的写法:
Array.prototype.myFunc = function myFunc() {
// implementation
};
复制代码
好的写法:
class SuperArray extends Array {
myFunc() {
// implementation
}
}
复制代码
判断条件
避免使用否定的条件
坏的写法:
function isUserNotBlocked(user) {
// implementation
}
if (!isUserNotBlocked(user)) {
// implementation
}
复制代码
好的写法:
function isUserBlocked(user) {
// implementation
}
if (isUserBlocked(user)) {
// implementation
}
复制代码
使用简短的条件
这个要求看上去简单,但是值得提醒
坏的写法:
if (isValid === true) {
// do something...
}
if (isValid === false) {
// do something...
}
复制代码
好的写法:
if (isValid) {
// do something...
}
if (!isValid) {
// do something...
}
复制代码
ES 类
尽可能使用类
建议使用类而不是用老式的直接定义函数的写法。
坏的写法:
const Person = function(name) {
if (!(this instanceof Person)) {
throw new Error("Instantiate Person with `new` keyword");
}
this.name = name;
};
Person.prototype.sayHello = function sayHello() {
/**/
};
const Student = function(name, school) {
if (!(this instanceof Student)) {
throw new Error("Instantiate Student with `new` keyword");
}
Person.call(this, name);
this.school = school;
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.printSchoolName = function printSchoolName() {
/**/
};
复制代码
好的写法:
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
/* ... */
}
}
class Student extends Person {
constructor(name, school) {
super(name);
this.school = school;
}
printSchoolName() {
/* ... */
复制代码
使用链式调用
使用函数调用链。像 jQuery,Lodash 都使用这个模式。你只需要在每一个函数的末尾返回this,之后的代码会更加的简洁。
坏的写法:
class Person {
constructor(name) {
this.name = name;
}
setSurname(surname) {
this.surname = surname;
}
setAge(age) {
this.age = age;
}
save() {
console.log(this.name, this.surname, this.age);
}
}
const person = new Person("John");
person.setSurname("Doe");
person.setAge(29);
person.save();
复制代码
好的写法:
class Person {
constructor(name) {
this.name = name;
}
setSurname(surname) {
this.surname = surname;
// Return this for chaining
return this;
}
setAge(age) {
this.age = age;
// Return this for chaining
return this;
}
save() {
console.log(this.name, this.surname, this.age);
// Return this for chaining
return this;
}
}
const person = new Person("John")
.setSurname("Doe")
.setAge(29)
.save();
复制代码
其它
总的来说,你不能写重复代码,不能留下一堆不再使用的函数,永远不会执行的代码(死代码)。