使用有準(zhǔn)確意義的變量名
在變量值不會改變時使用const聲明一個常量
對同一類型的變量使用相同的詞匯
使用可搜索的名稱(用var聲明全局的大寫變量)
使用解釋型的變量
bad:
const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
saveCityState(cityStateRegex.match(cityStateRegex)[1], cityStateRegex.match(cityStateRegex)[2]);
good:
const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
const match = cityStateRegex.match(cityStateRegex)
const city = match[1];
const state = match[2];
saveCityState(city, state);
- 短路語法比條件語句更清晰
- 函數(shù)參數(shù)理論上少于等于2個
- 一個函數(shù)只做一件事
- 函數(shù)名稱要說明他做的事
- 函數(shù)應(yīng)該只抽象一個層次
- 刪除重復(fù)代碼
- 使用默認(rèn)參數(shù)代替短路表達(dá)式
bad:
function writeForumComment(subject, body) {
subject = subject || 'No Subject';
body = body || 'No text';
}
good:
function writeForumComment(subject = 'No subject', body = 'No text') {
...
}
- 用Object.assign設(shè)置默認(rèn)對象
config = Object.assign({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
}, config);
- 不要把標(biāo)記用作函數(shù)參數(shù)(Boolean值)
bad:
function createFile(name, temp) {
if (temp) {
fs.create('./temp/' + name);
} else {
fs.create(name);
}
}
good:
function createTempFile(name) {
fs.create('./temp/' + name);
}
function createFile(name) {
fs.create(name);
}
- 避免否定條件
- 封裝條件
bad:
if (fsm.state === 'fetching' && isEmpty(listNode)) {
/// ...
}
good:
function shouldShowSpinner(fsm, listNode) {
return fsm.state === 'fetching' && isEmpty(listNode);
}
if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}
- 避免副作用
函數(shù)參數(shù)名和全局變量一樣時,將全局變量置于函數(shù)之后
- 喜歡上命令式編程之上的函數(shù)式編程
bad:
const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];
var totalOutput = 0;
for (var i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
good:
const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];
var totalOutput = programmerOutput
.map((programmer) => programmer.linesOfCode)
.reduce((acc, linesOfCode) => acc + linesOfCode, 0);
- 避免條件
- 避免類型檢查
- 不要過度優(yōu)化
bad:
for (var i = 0, len = list.length; i < len; i++) {
// ...
}
good:
for (var i = 0; i < list.length; i++) {
// ...
}
- 刪除不用的代碼(不要注釋代碼)
- 使用getter和setter
bad:
class BankAccount {
constructor() {
this.balance = 1000;
}
}
let bankAccount = new BankAccount();
// 支出
bankAccount.balance = bankAccount.balance - 100;
good:
class BankAccount {
constructor() {
this.balance = 1000;
}
// It doesn't have to be prefixed with `get` or `set` to be a getter/setter
withdraw(amount) {
if (verifyAmountCanBeDeducted(amount)) {
this.balance -= amount;
}
}
}
let bankAccount = new BankAccount();
bankAccount.withdraw(100);
- 讓對象擁有私有成員(通過函數(shù)return)
bad:
var Employee = function(name) {
this.name = name;
}
Employee.prototype.getName = function() {
return this.name;
}
var employee = new Employee('John Doe');
console.log('Employee name: ' + employee.getName()); // Employee name: John Doe
delete employee.name;
console.log('Employee name: ' + employee.getName()); // Employee name: undefined
good:
var Employee = (function() {
function Employee(name) {
this.getName = function() {
return name;
};
}
return Employee;
}());
var employee = new Employee('John Doe');
console.log('Employee name: ' + employee.getName()); // Employee name: John Doe
delete employee.name;
console.log('Employee name: ' + employee.getName()); // Employee name: John Doe
- 類-單一職責(zé)原則(SRP)
- 開放封裝原則(OCP)
- 里氏替換原則(LSP)
- 接口隔離原則(ISP)
- 依賴倒置原則(DIP)
- async/await
bad:(promise)
require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
.then(function(response) {
return require('fs-promise').writeFile('article.html', response);
})
.then(function() {
console.log('File written');
})
.catch(function(err) {
console.error(err);
})
good:
async function getCleanCodeArticle() {
try {
var request = await require('request-promise')
var response = await request.get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
var fileHandle = await require('fs-promise');
await fileHandle.writeFile('article.html', response);
console.log('File written');
} catch(err) {
console.log(err);
}
}
- 錯誤處理
try {
functionThatMightThrow();
} catch (error) {
// 選擇之一(比 console.log 更鬧心):
console.error(error);
// 另一個選擇:
notifyUserOfError(error);
// 另一個選擇:
reportErrorToService(error);
// 或者所有上述三種選擇庆揪!
}
- 使用一致的大小寫
- 調(diào)用者和被調(diào)用者盡可能的放在一起
- 刪除已注釋代碼及盡量少使用注釋
- 做有意義的區(qū)分,依義命名
不要使用如a1斤蔓,a2猎唁,a3...這樣沒有區(qū)分度的命名,用parent,children等有意義的區(qū)分
- 不要使用雙關(guān)語
如add监氢,使用append或insert這類動詞
- 變量,函數(shù)藤违,類的命名應(yīng)該盡量簡短浪腐,有具體意義(data,info都是一個意思)