本文是原作者根据《代码整洁之道》总结的适用于 JavaScript 软件工程的原则。
本文是对作者英文原文《Clean Code JavaScript》的翻译整理。
错误处理错误抛出非常必要,有助于定位运行状态中的程序产生错误的位置。
别忘了捕获错误
代码中 try/catch
的意味着你认为这里可能出现一些错误,你应该对这些可能的错误存在相应的处理方案。
Bad:
try {
functionThatMightThrow();
} catch (error) {
console.log(error);
}
Good:
try {
functionThatMightThrow();
} catch (error) {
// One option (more noisy than console.log):
console.error(error);
// Another option:
notifyUserOfError(error);
// Another option:
reportErrorToService(error);
// OR do all three!
}
不要忽略返回 rejected 的 promises
理由同 try/catch
。
Bad:
getdata()
.then(data => {
functionThatMightThrow(data);
})
.catch(error => {
console.log(error);
});
Good:
getdata()
.then(data => {
functionThatMightThrow(data);
})
.catch(error => {
// One option (more noisy than console.log):
console.error(error);
// Another option:
notifyUserOfError(error);
// Another option:
reportErrorToService(error);
// OR do all three!
});
代码规范
代码规范是约定行为,虽然不是必须遵守规则,但一旦团队约定,就应该遵守。例如参考的规范之一。
大小写一致
JS 是弱类型语言,合理的采用大小写可以得知关于变量/函数等的许多帮助信息。
这些规则是主观定义的,团队可以根据喜欢进行选择。重点在于无论选择何种风格,都需要注意保持一致性。
Bad:
var DAYS_IN_WEEK = 7;
var daysInMonth = 30;
var songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
var Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];
function eraseDatabase() {}
function restore_database() {}
class animal {}
class Alpaca {}
Good:
var DAYS_IN_WEEK = 7;
var DAYS_IN_MONTH = 30;
var songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
var artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];
function eraseDatabase() {}
function restoreDatabase() {}
class Animal {}
class Alpaca {}
调用函数的函数和被调函数应放在较近的位置
当函数间存在相互调用的情况时,应将两者置于较近的位置。
理想情况下,应将调用其他函数的函数写在被调用函数的上方。
Bad:
class PerformanceReview {
constructor(employee) {
this.employee = employee;
}
lookupPeers() {
return db.lookup(this.employee, 'peers');
}
lookupMananger() {
return db.lookup(this.employee, 'manager');
}
getPeerReviews() {
let peers = this.lookupPeers();
// ...
}
perfReview() {
getPeerReviews();
getManagerReview();
getSelfReview();
}
getManagerReview() {
let manager = this.lookupManager();
}
getSelfReview() {
// ...
}
}
let review = new PerformanceReview(user);
review.perfReview();
Good:
class PerformanceReview {
constructor(employee) {
this.employee = employee;
}
perfReview() {
getPeerReviews();
getManagerReview();
getSelfReview();
}
getPeerReviews() {
let peers = this.lookupPeers();
// ...
}
lookupPeers() {
return db.lookup(this.employee, 'peers');
}
getManagerReview() {
let manager = this.lookupManager();
}
lookupMananger() {
return db.lookup(this.employee, 'manager');
}
getSelfReview() {
// ...
}
}
let review = new PerformanceReview(employee);
review.perfReview();
注释
只对存在一定业务逻辑复杂性的代码进行注释
注释并不是必须的,好的代码是能够让人一目了然,不用过多无谓的注释。
Bad:
function hashIt(data) {
// The hash
var hash = 0;
// Length of string
var length = data.length;
// Loop through every character in data
for (var i = 0; i < length; i++) {
// Get character code.
var char = data.charCodeAt(i);
// Make the hash
hash = ((hash << 5) - hash) + char;
// Convert to 32-bit integer
hash = hash & hash;
}
}
Good:
function hashIt(data) {
var hash = 0;
var length = data.length;
for (var i = 0; i < length; i++) {
var char = data.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
// Convert to 32-bit integer
hash = hash & hash;
}
}
不要在代码库中遗留被注释掉的代码
git 等版本控制的存在是有原因之一就是将旧代码保存在于 history 中,而不是注释中。
Bad:
doStuff();
// doOtherStuff();
// doSomeMoreStuff();
// doSoMuchStuff();
Good:
doStuff();
不需要添加版本更新相关注释
应该使用版本控制记录更新历史,废弃代码、被注释的代码,以及用注释记录版本更新都是没有必要的。
需要时,可以使用 git log
获取历史版本。
Bad:
/**
* 2016-12-20: Removed monads, didn't understand them (RM)
* 2016-10-01: Improved using special monads (JP)
* 2016-02-03: Removed type-checking (LI)
* 2015-03-14: Added combine with type-checking (JR)
*/
function combine(a, b) {
return a + b;
}
Good:
function combine(a, b) {
return a + b;
}
避免位置符号分割标记
这些符号标识会使代码混乱,通常采用适当的空行和缩进即可。
Bad:
////////////////////////////////////////////////////////////////////////////////
// Scope Model Instantiation
////////////////////////////////////////////////////////////////////////////////
let $scope.model = {
menu: 'foo',
nav: 'bar'
};
////////////////////////////////////////////////////////////////////////////////
// Action setup
////////////////////////////////////////////////////////////////////////////////
let actions = function() {
// ...
}
Good:
let $scope.model = {
menu: 'foo',
nav: 'bar'
};
let actions = function() {
// ...
}
避免在源文件中写入法律声明
应当将你的 LICENSE
文件置于源码目录树的根目录。
Bad:
/*
The MIT License (MIT)
Copyright (c) 2016 Ryan McDermott
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
*/
function calculateBill() {
// ...
}
Good:
function calculateBill() {
// ...
}