An article teaches you to write clean JavaScript code
- 2021-11-13 06:29:37
- OfStack
Use meaningful names
Avoid adding unnecessary context
Avoid hard-coded values
2. Functions
Use meaningful names
Use default parameters
Limit the number of parameters
Avoid doing too many things in 1 function
Avoid using Boolean flags as parameters
Avoid writing duplicate code
Avoid side effects
3. Conditional statements
Use nonnegative conditions
Use abbreviations whenever possible
Avoid excessive branching
Prefer map to switch statement
4. Concurrent
Avoid callbacks
5. Error handling
6. Notes
Only annotate business logic
Use version control
Summarize
1 clean piece of code, you can read, reuse and refactor very easily. Writing clean code is very important because in our daily work, you are not just writing code for yourself. In fact, you also need to consider a group of colleagues who need to understand, edit and build your code.
1. Variables
Use meaningful names
Variable names should be descriptive and meaningful, and JavaScript variables should be named in hump case (camelCase).
// Don't ❌
const foo = "JDoe@example.com";
const bar = "John";
const age = 23;
const qux = true;
// Do ✅
const email = "John@example.com";
const firstName = "John";
const age = 23;
const isActive = true
Boolean variables usually need to answer specific questions, such as:
isActive
didSubscribe
hasLinkedAccount
Avoid adding unnecessary context
Do not add redundant contexts to variable names when an object or class already contains context names.
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
Avoid hard-coded values
Be sure to declare meaningful and searchable constants instead of inserting a constant value directly. Global constants can be named in the SCREAMING_SNAKE_CASE style.
// Don't ❌
setTimeout(clearSessionData, 900000);
// Do ✅
const SESSION_DURATION_MS = 15 * 60 * 1000;
setTimeout(clearSessionData, SESSION_DURATION_MS);
2. Functions
Use meaningful names
The function name needs to describe the actual function, even if it is very long. Function names usually use verbs, but a function that returns a Boolean value may be an exception-it can take the form of a yes or no question, and the function name should also be hump.
// Don't ❌
function toggle() {
// ...
}
function agreed(user) {
// ...
}
// Do ✅
function toggleThemeSwitcher() {
// ...
}
function didAgreeToAllTerms(user) {
// ...
}
Use default parameters
Default parameter ratio & & Or it is cleaner to use extra conditional statements in the function body.
// Don't ❌
function printAllFilesInDirectory(dir) {
const directory = dir || "./";
// ...
}
// Do ✅
function printAllFilesInDirectory(dir = "./") {
// ...
}
Limit the number of parameters
Although this rule may be controversial, it is best for functions to have less than three parameters. If there are many parameters, it may be one of the following two situations:
This function does too many things and should be split. The data passed to a function is related in some way and can be passed as a private data structure.
// Don't ❌
function sendPushNotification(title, message, image, isSilent, delayMs) {
// ...
}
sendPushNotification("New Message", "...", "http://...", false, 1000);
// Do ✅
function sendPushNotification({ title, message, image, isSilent, delayMs }) {
// ...
}
const notificationConfig = {
title: "New Message",
message: "...",
image: "http://...",
isSilent: false,
delayMs: 1000,
};
sendPushNotification(notificationConfig);
Avoid doing too many things in 1 function
A function should do one thing at a time, which helps reduce the size and complexity of the function and makes testing, debugging, and refactoring easier.
/ Don't ❌
function pingUsers(users) {
users.forEach((user) => {
const userRecord = database.lookup(user);
if (!userRecord.isActive()) {
ping(user);
}
});
}
// Do ✅
function pingInactiveUsers(users) {
users.filter(!isUserActive).forEach(ping);
}
function isUserActive(user) {
const userRecord = database.lookup(user);
return userRecord.isActive();
}
Avoid using Boolean flags as parameters
Parameters of a function with Boolean flags mean that the function can be simplified.
// Don't ❌
function createFile(name, isPublic) {
if (isPublic) {
fs.create(`./public/${name}`);
} else {
fs.create(name);
}
}
// Do ✅
function createFile(name) {
fs.create(name);
}
function createPublicFile(name) {
createFile(`./public/${name}`);
}
Avoid writing duplicate code
If you write repeated code, every time there is a logical change, you need to change multiple positions.
// Don't ❌
function renderCarsList(cars) {
cars.forEach((car) => {
const price = car.getPrice();
const make = car.getMake();
const brand = car.getBrand();
const nbOfDoors = car.getNbOfDoors();
render({ price, make, brand, nbOfDoors });
});
}
function renderMotorcyclesList(motorcycles) {
motorcycles.forEach((motorcycle) => {
const price = motorcycle.getPrice();
const make = motorcycle.getMake();
const brand = motorcycle.getBrand();
const seatHeight = motorcycle.getSeatHeight();
render({ price, make, brand, nbOfDoors });
});
}
// Do ✅
function renderVehiclesList(vehicles) {
vehicles.forEach((vehicle) => {
const price = vehicle.getPrice();
const make = vehicle.getMake();
const brand = vehicle.getBrand();
const data = { price, make, brand };
switch (vehicle.type) {
case "car":
data.nbOfDoors = vehicle.getNbOfDoors();
break;
case "motorcycle":
data.seatHeight = vehicle.getSeatHeight();
break;
}
render(data);
});
}
Avoid side effects
In JavaScript, you should prefer functional mode to imperative mode. In other words, in most cases, we should keep the function pure. Side effects may modify shared state and resources, resulting in some strange problems. All side effects should be managed centrally. For example, if you need to change global variables or modify files, you can write an util to do this.
// Don't ❌
let date = "21-8-2021";
function splitIntoDayMonthYear() {
date = date.split("-");
}
splitIntoDayMonthYear();
// Another function could be expecting date as a string
console.log(date); // ['21', '8', '2021'];
// Do ✅
function splitIntoDayMonthYear(date) {
return date.split("-");
}
const date = "21-8-2021";
const newDate = splitIntoDayMonthYear(date);
// Original vlaue is intact
console.log(date); // '21-8-2021';
console.log(newDate); // ['21', '8', '2021'];
In addition, if you pass a variable value to a function, you should directly clone a new value and return it instead of directly changing it.
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
0
3. Conditional statements
Use nonnegative conditions
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
1
Use abbreviations whenever possible
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
2
Avoid excessive branching
Early return will make your code linearized, more readable and less complicated.
// Don't ❌
function addUserService(db, user) {
if (!db) {
if (!db.isConnected()) {
if (!user) {
return db.insert("users", user);
} else {
throw new Error("No user");
}
} else {
throw new Error("No database connection");
}
} else {
throw new Error("No database");
}
}
// Do ✅
function addUserService(db, user) {
if (!db) throw new Error("No database");
if (!db.isConnected()) throw new Error("No database connection");
if (!user) throw new Error("No user");
return db.insert("users", user);
}
Prefer map to switch statement
It can reduce complexity and improve performance.
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
4
Use optional links
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
5
4. Concurrent
Avoid callbacks
Callbacks are confusing, which leads to too deep nesting of code. Promise is used instead of callbacks.
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
6
5. Error handling
Handling Thrown Errors and promise for reject
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
7
6. Notes
Only annotate business logic
Readable code prevents you from over-commenting, so you should only comment complex logic.
// Don't ❌
function generateHash(str) {
// Hash variable
let hash = 0;
// Get the length of the string
let length = str.length;
// If the string is empty return
if (!length) {
return hash;
}
// Loop through every character in the string
for (let i = 0; i < length; i++) {
// Get character code.
const char = str.charCodeAt(i);
// Make the hash
hash = (hash << 5) - hash + char;
// Convert to 32-bit integer
hash &= hash;
}
}
// Do ✅
function generateHash(str) {
let hash = 0;
let length = str.length;
if (!length) {
return hash;
}
for (let i = 0; i < length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
Use version control
There is no need to keep version history comments in the code. If you want to check it, you can search it directly with git log. .
// Don't ❌
const user = {
userId: "296e2589-7b33-400a-b762-007b730c8e6d",
userEmail: "JDoe@example.com",
userFirstName: "John",
userLastName: "Doe",
userAge: 23,
};
user.userId;
// Do ✅
const user = {
id: "296e2589-7b33-400a-b762-007b730c8e6d",
email: "JDoe@example.com",
firstName: "John",
lastName: "Doe",
age: 23,
};
user.id;
9
Ok, go and write your beautiful code!