1. Strong type inspection
Replace with = = ===
// If not handled properly, it will greatly affect the program logic. It's like, you want to go left, but for some reason, you go right 0 == false // true 0 === false // false 2 == "2" // true 2 === "2" // false
// example const value = "500"; if (value === 500) { console.log(value); // If the conditions are not established, it will not enter } if (value === "500") { console.log(value); // If the conditions are established, it will enter }
2. Variables
Variables are named in a well-known way. In this way, when one sees them, it is easy to search and understand. Bad way:
let daysSLV = 10; let y = new Date().getFullYear(); let ok; if (user.age > 30) { ok = true; } Good way: const MAX_AGE = 30; let daysSinceLastVisit = 10; let currentYear = new Date().getFullYear(); ... const isUserOlderThanAllowed = user.age > MAX_AGE;
Do not add additional unnecessary words to variable names.
Bad way: let nameValue; let theProduct; Good way: let name; let product; Do not abbreviate variable context. Bad way: const users = ["John", "Marco", "Peter"]; users.forEach(u => { doSomething(); doSomethingElse(); // ... // ... // ... // ... // When there is a lot of code above, what the hell is this' u ' register(u); }); Good way: const users = ["John", "Marco", "Peter"]; users.forEach(user => { doSomething(); doSomethingElse(); // ... // ... // ... // ... register(user); }); Do not add unnecessary context. Bad way: const user = { userName: "John", userSurname: "Doe", userAge: "28" }; ... user.userName; Good way: const user = { name: "John", surname: "Doe", age: "28" }; ... user.name;
3. Function
Use long descriptive names. Considering that the function represents a certain behavior, the function name should be a verb or short} language to explain the intention behind it and the intention of parameters. The name of the function should indicate what they did. Bad way:
function notif(user) { // implementation } Good way: function notifyUser(emailAddress) { // implementation }
Avoid using a large number of parameters. Ideally, a function should specify two or fewer parameters. The fewer parameters, the easier it is to test the function. Objects can be used when there are many parameters. Bad way:
function getUsers(fields, fromDate, toDate) { // implementation } Good way: function getUsers({ fields, fromDate, toDate }) { // implementation } getUsers({ fields: ['name', 'surname', 'email'], fromDate: '2019-01-01', toDate: '2019-01-18' });
Replace | operation with default parameters
Bad way: function createShape(type) { const shapeType = type || "cube"; // ... } Good way: function createShape(type = "cube") { // ... }
A function should only do one thing. Do not perform multiple operations in a function.
Bad way: function notifyUsers(users) { users.forEach(user => { const userRecord = database.lookup(user); if (userRecord.isVerified()) { notify(user); } }); } Good way: function notifyVerifiedUsers(users) { users.filter(isUserVerified).forEach(notify); } function isUserVerified(user) { const userRecord = database.lookup(user); return userRecord.isVerified(); }
Use object Assign sets the default value of the object.
Bad way: const shapeConfig = { type: "cube", width: 200, height: null }; function createShape(config) { config.type = config.type || "cube"; config.width = config.width || 250; config.height = config.height|| 250; } createShape(shapeConfig); Good way: const shapeConfig = { type: "cube", width: 200 // Exclude the 'height' key }; function createShape(config) { config = Object.assign( { type: "cube", width: 250, height: 250 }, config ); ... } createShape(shapeConfig);
Don't use flags as arguments because they tell the function to do more than it should.
Bad way: function createFile(name, isPublic) { if (isPublic) { fs.create(`./public/${name}`); } else { fs.create(name); } } Good way: function createFile(name) { fs.create(name); } function createPublicFile(name) { createFile(`./public/${name}`); }
Do not contaminate global variables. If you need to extend an existing object, use ES classes and inheritance instead of creating functions on the prototype chain of the native object.
Bad way: Array.prototype.myFunc = function myFunc() { // implementation }; Good way: class SuperArray extends Array { myFunc() { // implementation } }
4. Conditions
Avoid negative conditions.
Bad way: function isUserNotBlocked(user) { // implementation } if (!isUserNotBlocked(user)) { // implementation } Good way: function isUserBlocked(user) { // implementation } if (isUserBlocked(user)) { // implementation }
Abbreviation of service conditions. This may be trivial, but it is worth mentioning. Use this method only for Boolean values, and if you are sure that the value will not be undefined or null, use this method.
Bad way: if (isValid === true) { // do something... } if (isValid === false) { // do something... } Good way: if (isValid) { // do something... } if (!isValid) { // do something... }
Avoid conditional sentences as much as possible, but use polymorphism and inheritance.
Bad way: class Car { // ... getMaximumSpeed() { switch (this.type) { case "Ford": return this.someFactor() + this.anotherFactor(); case "Mazda": return this.someFactor(); case "McLaren": return this.someFactor() - this.anotherFactor(); } } } Good way: class Car { // ... } class Ford extends Car { // ... getMaximumSpeed() { return this.someFactor() + this.anotherFactor(); } } class Mazda extends Car { // ... getMaximumSpeed() { return this.someFactor(); } } class McLaren extends Car { // ... getMaximumSpeed() { return this.someFactor() - this.anotherFactor(); } }
5. Category
class is a new syntax sugar in JavaScript. Everything works just like the previous prototype, but it looks different now. You should like them more than the ordinary functions of ES5.
Bad way: const Person = function(name) { if (!(this instanceof Person)) { throw new Error("Instantiate Person with `new` keyword"); } this.name = name; }; Person.prototype.sayHello = function sayHello() { /**/ }; const Student = function(name, school) { if (!(this instanceof Student)) { throw new Error("Instantiate Student with `new` keyword"); } Person.call(this, name); this.school = school; }; Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; Student.prototype.printSchoolName = function printSchoolName() { /**/ }; Good way: class Person { constructor(name) { this.name = name; } sayHello() { /* ... */ } } class Student extends Person { constructor(name, school) { super(name); this.school = school; } printSchoolName() { /* ... */ } }
Use links. Many libraries, such as jQuery and lodash, use this pattern. In a class, just return this at the end of each function to link more methods of the class to it.
Bad way: class Person { constructor(name) { this.name = name; } setSurname(surname) { this.surname = surname; } setAge(age) { this.age = age; } save() { console.log(this.name, this.surname, this.age); } } const person = new Person("John"); person.setSurname("Doe"); person.setAge(29); person.save(); Good way: class Person { constructor(name) { this.name = name; } setSurname(surname) { this.surname = surname; // Return this for chaining return this; } setAge(age) { this.age = age; // Return this for chaining return this; } save() { console.log(this.name, this.surname, this.age); // Return this for chaining return this; } } const person = new Person("John") .setSurname("Doe") .setAge(29) .save();
summary
This is only a small part of the improved code. Generally speaking, the principles mentioned here are the principles that people usually don't abide by. They tried to do it, but for various reasons, they didn't stick to it. Perhaps at the beginning of the project, the code is concise, but when it comes to completing by the deadline, these principles are often ignored and transferred to the "TODO" or "reducer" section. At this point, your customers prefer you to meet the deadline rather than write concise code.