(1) Use Default parameter passing
// Bad:
function createMicrobrewery( name ) {
const breweryName = name || 'Hipster Brew Co.';
// ...
}
// Good:
function createMicrobrewery( name = 'Hipster Brew Co.' ) {
// ...
}
(2) function parameters (preferably 2 or less)
If more than two parameters, it is recommended to use deconstruction of syntax ES6, regardless of the order parameter.
// Bad:
function createMenu( title, body, buttonText, cancellable ) {
// ...
}
// Good:
function createMenu( { title, body, buttonText, cancellable } ) {
// ...
}
createMenu({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
});
(3) a method only one thing
This is a popular old rules in the field of software engineering. Strict compliance with this rule will make your code more readable and easier to reconstruct.
// Bad:
function emailClients( clients ) {
clients.forEach( client => {
const clientRecord = database.lookup( client );
if ( clientRecord.isActive() ) {
email( client );
}
});
}
// Good:
function emailActiveClients( clients ) {
clients
.filter( isActiveClient )
.forEach( email );
}
function isActiveClient( client ) {
const clientRecord = database.lookup( client );
return clientRecord.isActive();
}
(4) Remove duplicate code, merge similar function
Although it is often the same function, but because of one or two different points, so you have to write two almost identical functions.
// Bad:
function showDeveloperList(developers) {
developers.forEach((developer) => {
const expectedSalary = developer.calculateExpectedSalary();
const experience = developer.getExperience();
const githubLink = developer.getGithubLink();
const data = {
expectedSalary,
experience,
githubLink
};
render(data);
});
}
function showManagerList(managers) {
managers.forEach((manager) => {
const expectedSalary = manager.calculateExpectedSalary();
const experience = manager.getExperience();
const portfolio = manager.getMBAProjects();
const data = {
expectedSalary,
experience,
portfolio
};
render(data);
});
}
// Good:
function showEmployeeList(employees) {
employees.forEach(employee => {
const expectedSalary = employee.calculateExpectedSalary();
const experience = employee.getExperience();
const data = {
expectedSalary,
experience,
};
switch(employee.type) {
case 'develop':
data.githubLink = employee.getGithubLink();
break
case 'manager':
data.portfolio = employee.getMBAProjects();
break
}
render(data);
})
}
(5) using set default properties Object.assign
// Bad:
const menuConfig = {
title: null,
body: 'Bar',
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);
// Good:
const menuConfig = {
title: 'Order',
// 不包含 body
buttonText: 'Send',
cancellable: true
};
function createMenu(config) {
config = Object.assign({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
}, config);
// config : {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// ...
}
createMenu(menuConfig);
(6) Try not to write global method
In JavaScript, never to global pollution, it will produce unexpected bug in a production environment.
For example, you add such a method on Array.prototype diff determines two different arrays. And your colleagues intend to do something similar, but his diff method is used to determine the top two arrays of different elements. Obviously your method will produce conflict, problems of this sort we can extend the Array with grammar ES2015 / ES6's.
// Bad:
Array.prototype.diff = function diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
};
// Good:
class SuperArray extends Array {
diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
}
}
(7) Do not try to use "non" conditionals
// Bad:
function isDOMNodeNotPresent(node) {
// ...
}
if (!isDOMNodeNotPresent(node)) {
// ...
}
// Good:
function isDOMNodePresent(node) {
// ...
}
if (isDOMNodePresent(node)) {
// ...
}
(8) Try not to write global method
Before ES6, no grammar class, can only simulate class constructor, readability is very poor.
// Good:
// 动物
class Animal {
constructor(age) {
this.age = age
};
move() {};
}
// 哺乳动物
class Mammal extends Animal{
constructor(age, furColor) {
super(age);
this.furColor = furColor;
};
liveBirth() {};
}
// 人类
class Human extends Mammal{
constructor(age, furColor, languageSpoken) {
super(age, furColor);
this.languageSpoken = languageSpoken;
};
speak() {};
}
(9) the use of chained calls
This mode is very useful, you can have a lot of use in the library. It makes your code simple and elegant.
// Bad:
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
}
setMake(make) {
this.make = make;
}
setModel(model) {
this.model = model;
}
setColor(color) {
this.color = color;
}
save() {
console.log(this.make, this.model, this.color);
}
}
const car = new Car('Ford','F-150','red');
car.setColor('pink');
car.save();
// Good:
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
}
setMake(make) {
this.make = make;
// NOTE: Returning this for chaining
return this;
}
setModel(model) {
this.model = model;
// NOTE: Returning this for chaining
return this;
}
setColor(color) {
this.color = color;
// NOTE: Returning this for chaining
return this;
}
save() {
console.log(this.make, this.model, this.color);
// NOTE: Returning this for chaining
return this;
}
}
const car = new Car("Ford", "F-150", "red").setColor("pink").save();
(10) promise to use or Async / Await replaced callback
// Bad:
get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', (requestErr, response) => {
if (requestErr) {
console.error(requestErr);
} else {
writeFile('article.html', response.body, (writeErr) => {
if (writeErr) {
console.error(writeErr);
} else {
console.log('File written');
}
});
}
});
// Good:
get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
.then((response) => {
return writeFile('article.html', response);
})
.then(() => {
console.log('File written');
})
.catch((err) => {
console.error(err);
});
// perfect:
async function getCleanCodeArticle() {
try {
const response = await get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
await writeFile('article.html', response);
console.log('File written');
} catch(err) {
console.error(err);
}
}