不必严格遵守本文的所有原则,有时少遵守一些效果可能会更好,具体应根据实际情况决定。这是根据《代码整洁之道》作者多年经验整理的代码优化建议,但也仅仅只是一份建议。
软件工程已经发展了50多年,至今仍在不断前进。现在,把这些原则当作试金石,尝试将他们作为团队代码质量考核的标准之一吧。
最后你需要知道的是,这些东西不会让你立刻变成一个优秀的工程师,长期奉行他们也并不意味着你能够高枕无忧不再犯错。千里之行,始于足下。我们需要时常和同行们进行代码评审,不断优化自己的代码。不要惧怕改善代码质量所需付出的努力,加油。
变量
使用有意义,可读性好的变量名
反例:
var yyyymmdstr = moment().format('YYYY/MM/DD');
正例:
var yearMonthDay = moment().format('YYYY/MM/DD');
使用ES6的const定义常量
反例中使用"var"定义的"常量"是可变的。
在声明一个常量时,该常量在整个程序中都应该是不可变的。
反例:
var FirsT_US_PRESIDENT = "George Washington";
正例:
const FirsT_US_PRESIDENT = "George Washington";
对功能类似的变量名采用统一的命名风格
反例:
getUserInfo();
getClientData();
getCustomerRecord();
正例:
getUser();
使用易于检索名称
我们需要阅读的代码远比自己写的要多,使代码拥有良好的可读性且易于检索非常重要。阅读变量名晦涩难懂的代码对读者来说是一种相当糟糕的体验。
让你的变量名易于检索。
反例:
// 525600 是什么?
for (var i = 0; i < 525600; i++) {
runcronJob();
}
正例:
// Declare them as capitalized `var` globals.
var MINUTES_IN_A_YEAR = 525600;
for (var i = 0; i < MINUTES_IN_A_YEAR; i++) {
runcronJob();
}
使用说明变量(即有意义的变量名)
反例:
const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
saveCityState(cityStateRegex.match(cityStateRegex)[1],cityStateRegex.match(cityStateRegex)[2]);
正例:
const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
const match = cityStateRegex.match(cityStateRegex)
const city = match[1];
const state = match[2];
saveCityState(city,state);
不要绕太多的弯子
显式优于隐式。
反例:
var locations = ['Austin','New York','San Francisco'];
locations.forEach((l) => {
doStuff();
doSomeOtherStuff();
...
...
...
// l是什么?
dispatch(l);
});
正例:
var locations = ['Austin','San Francisco'];
locations.forEach((location) => {
doStuff();
doSomeOtherStuff();
...
...
...
dispatch(location);
});
避免重复的描述
当类/对象名已经有意义时,对其变量进行命名不需要再次重复。
反例:
var Car = {
carMake: 'Honda',carModel: 'Accord',carColor: 'Blue'
};
function paintCar(car) {
car.carColor = 'Red';
}
正例:
var Car = {
make: 'Honda',model: 'Accord',color: 'Blue'
};
function paintCar(car) {
car.color = 'Red';
}
避免无意义的条件判断
反例:
function createMicrobrewery(name) {
var breweryName;
if (name) {
breweryName = name;
} else {
breweryName = 'Hipster Brew Co.';
}
}
正例:
function createMicrobrewery(name) {
var breweryName = name || 'Hipster Brew Co.'
}
函数
函数参数 (理想情况下应不超过2个)
限制函数参数数量很有必要,这么做使得在测试函数时更加轻松。过多的参数将导致难以采用有效的测试用例对函数的各个参数进行测试。
应避免三个以上参数的函数。通常情况下,参数超过两个意味着函数功能过于复杂,这时需要重新优化你的函数。当确实需要多个参数时,大多情况下可以考虑这些参数封装成一个对象。
JS定义对象非常方便,当需要多个参数时,可以使用一个对象进行替代。
反例:
function createMenu(title,body,buttonText,cancellable) {
...
}
正例:
var menuConfig = {
title: 'Foo',body: 'Bar',buttonText: 'Baz',cancellable: true
}
function createMenu(menuConfig) {
...
}
函数功能的单一性
这是软件功能中最重要的原则之一。
功能不单一的函数将导致难以重构、测试和理解。功能单一的函数易于重构,并使代码更加干净。
反例:
function emailClients(clients) {
clients.forEach(client => {
let clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
正例:
function emailClients(clients) {
clients.forEach(client => {
emailClientIfNeeded(client);
});
}
function emailClientIfNeeded(client) {
if (isClientActive(client)) {
email(client);
}
}
function isClientActive(client) {
let clientRecord = database.lookup(client);
return clientRecord.isActive();
}
函数名应明确表明其功能
反例:
function dateAdd(date,month) {
// ...
}
let date = new Date();
// 很难理解dateAdd(date,1)是什么意思
正例:
function dateAddMonth(date,month) {
// ...
}
let date = new Date();
dateAddMonth(date,1);
函数应该只做一层抽象
当函数的需要的抽象多于一层时通常意味着函数功能过于复杂,需将其进行分解以提高其可重用性和可测试性。
反例:
function parseBetterJSAlternative(code) {
let REGEXES = [
// ...
];
let statements = code.split(' ');
let tokens;
REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...
})
});
let ast;
tokens.forEach((token) => {
// lex...
});
ast.forEach((node) => {
// parse...
})
}
正例:
function tokenize(code) {
let REGEXES = [
// ...
];
let statements = code.split(' ');
let tokens;
REGEXES.forEach((REGEX) => {
statements.forEach((statement) => {
// ...
})
});
return tokens;
}
function lexer(tokens) {
let ast;
tokens.forEach((token) => {
// lex...
});
return ast;
}
function parseBetterJSAlternative(code) {
let tokens = tokenize(code);
let ast = lexer(tokens);
ast.forEach((node) => {
// parse...
})
}
移除重复的代码
永远、永远、永远不要在任何循环下有重复的代码。
这种做法毫无意义且潜在危险极大。重复的代码意味着逻辑变化时需要对不止一处进行修改。JS弱类型的特点使得函数拥有更强的普适性。好好利用这一优点吧。
反例:
function showDeveloperList(developers) {
developers.forEach(developers => {
var expectedSalary = developer.calculateExpectedSalary();
var experience = developer.getExperience();
var githubLink = developer.getGithubLink();
var data = {
expectedSalary: expectedSalary,experience: experience,githubLink: githubLink
};
render(data);
});
}
function showManagerList(managers) {
managers.forEach(manager => {
var expectedSalary = manager.calculateExpectedSalary();
var experience = manager.getExperience();
var portfolio = manager.getMBAProjects();
var data = {
expectedSalary: expectedSalary,portfolio: portfolio
};
render(data);
});
}
正例:
function showList(employees) {
employees.forEach(employee => {
var expectedSalary = employee.calculateExpectedSalary();
var experience = employee.getExperience();
var portfolio;
if (employee.type === 'manager') {
portfolio = employee.getMBAProjects();
} else {
portfolio = employee.getGithubLink();
}
var data = {
expectedSalary: expectedSalary,portfolio: portfolio
};
render(data);
});
}
采用默认参数精简代码
反例:
function writeForumComment(subject,body) {
subject = subject || 'No Subject';
body = body || 'No text';
}
正例:
function writeForumComment(subject = 'No subject',body = 'No text') {
...
}
使用Object.assign设置默认对象
反例:
var menuConfig = {
title: null,buttonText: null,cancellable: true
}
function createMenu(config) {
config.title = config.title || 'Foo'
config.body = config.body || 'Bar'
config.buttonText = config.buttonText || 'Baz'
config.cancellable = config.cancellable === undefined ? config.cancellable : true;
}
createMenu(menuConfig);
正例:
var menuConfig = {
title: 'Order',// User did not include 'body' key
buttonText: 'Send',cancellable: true
}
function createMenu(config) {
config = Object.assign({
title: 'Foo',cancellable: true
},config);
// con<a href="https://www.jb51.cc/tag/fig/" target="_blank" class="keywords">fig</a> <a href="https://www.jb51.cc/tag/Now/" target="_blank" class="keywords">Now</a> equals: {title: "Order",body: "Bar",buttonText: "Send",cancellable: true}
// ...
}
createMenu(menuConfig);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。