An article teaches you to write clean JavaScript code

An article teaches you to write clean JavaScript code

A clean code makes it easy to read, reuse, and refactor. Writing clean code is very important because in our daily work, you are not just writing code for yourself. In reality, 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. JavaScript variables should be named using camelCase.

// Don't ❌
const foo = "[email protected]";
const bar = "John";
const age = 23;
const qux = true;

// Do ✅
const email = "[email protected]";
const firstName = "John";
const age = 23;
const isActive = true

Boolean variables are often needed to answer specific questions, such as:

isActive
didSubscribe
hasLinkedAccount

Avoid adding unnecessary context

Do not add redundant context to variable names when the object or class already contains the naming context.

// Don't ❌
const user = {
  userId: "296e2589-7b33-400a-b762-007b730c8e6d",
  userEmail: "[email protected]",
  userFirstName: "John",
  userLastName: "Doe",
  userAge: 23,
};

user.userId;

// Do ✅
const user = {
  id: "296e2589-7b33-400a-b762-007b730c8e6d",
  email: "[email protected]",
  firstName: "John",
  lastName: "Doe",
  age: 23,
};

user.id;

Avoid hard-coded values

Make sure to declare meaningful and searchable constants rather than inserting a constant value directly. Global constants can be named using 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

Function names need to describe what the function actually does, even if they are long. Function names usually use verbs, but a function returning a Boolean value may be an exception — it can be in the form of a yes or no question, and the function name should also be camel case.

// Don't ❌
function toggle() {
  // ...
}

function agreed(user) {
  // ...
}

// Do ✅
function toggleThemeSwitcher() {
  // ...
}

function didAgreeToAllTerms(user) {
  // ...
}

Using default parameters

Default parameters are cleaner than && || or using extra conditionals within 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 to have functions with 3 or fewer parameters. If there are many parameters, it may be one of the following two situations:

  • This function does too much and should be broken up.
  • Data passed to a function that is related in some way can be passed as a specialized 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 much in one 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

Functions with boolean flags as parameters 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 duplicate code, every time the logic changes, you need to change multiple places.

// 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 the functional paradigm over the imperative paradigm. In other words, we should keep functions pure in most cases. Side effects may modify shared state and resources, causing strange problems. All side effects should be managed centrally. For example, if you need to change global variables or modify files, you can write a util specifically 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'];

Also, if you pass a mutable value to a function, you should always clone the value and return it instead of mutating it.

// Don't ❌
function enrollStudentInCourse(course, student) {
  course.push({ student, enrollmentDate: Date.now() });
}

// Do ✅
function enrollStudentInCourse(course, student) {
  return [...course, { student, enrollmentDate: Date.now() }];
}

3. Conditional Statements

Using non-negative conditions

// Don't ❌
function isUserNotVerified(user) {
  // ...
}

if (!isUserNotVerified(user)) {
  // ...
}

// Do ✅
function isUserVerified(user) {
  // ...
}

if (isUserVerified(user)) {
  // ...
}

Use abbreviations whenever possible

// Don't ❌
if (isActive === true) {
  // ...
}

if (firstName !== "" && firstName !== null && firstName !== undefined) {
  // ...
}

const isUserEligible = user.isVerified() && user.didSubscribe() ? true : false;

// Do ✅
if (isActive) {
  // ...
}

if (!!firstName) {
  // ...
}

const isUserEligible = user.isVerified() && user.didSubscribe();

Avoid too many branches

Returning early makes your code more linear, more readable, and less complex.

// 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 over switch statements

It can reduce complexity and improve performance.

// Don't ❌
const getColorByStatus = (status) => {
  switch (status) {
    case "success":
      return "green";
    case "failure":
      return "red";
    case "warning":
      return "yellow";
    case "loading":
    default:
      return "blue";
  }
};

// Do ✅
const statusColors = {
  success: "green",
  failure: "red",
  warning: "yellow",
  loading: "blue",
};

const getColorByStatus = (status) => statusColors[status] || "blue";

Using optional chaining

const user = {
  email: "[email protected]",
  billing:
    iban: "...",
    swift: "...",
    address:
      street: "Some Street Name",
      state: "CA",
    },
  },
};

// Don't ❌
const email = (user && user.email) || "N/A";
const street =
  (user &&
    user.billing &&
    user.billing.address &&
    user.billing.address.street) ||
  "N/A";
const state =
  (user &&
    user.billing &&
    user.billing.address &&
    user.billing.address.state) ||
  "N/A";

// Do ✅
const email = user?.email ?? "N/A";
const street = user?.billing?.address?.street ?? "N/A";
const street = user?.billing?.address?.state ?? "N/A";

4. Concurrency

Avoid callbacks

Callbacks are confusing and can cause your code to be nested too deeply. Use Promises instead of callbacks.

// Don't ❌
getUser(function (err, user) {
  getProfile(user, function (err, profile) {
    getAccount(profile, function (err, account) {
      getReports(account, function (err, reports) {
        sendStatistics(reports, function (err) {
          console.error(err);
        });
      });
    });
  });
});

// Do ✅
getUser()
  .then(getProfile)
  .then(getAccount)
  .then(getReports)
  .then(sendStatistics)
  .catch((err) => console.error(err));

// or using Async/Await ✅✅

async function sendUserStatistics() {
  try {
    const user = await getUser();
    const profile = await getProfile(user);
    const account = await getAccount(profile);
    const reports = await getReports(account);
    return sendStatistics(reports);
  } catch (e) {
    console.error(err);
  }
}

5. Error handling

Handling thrown errors and rejected promises

/ Don't ❌
try {
  // Possible erronous code
} catch (e) {
  console.log(e);
}

// Do ✅
try {
  // Possible erronous code
} catch (e) {
  // Follow the most applicable (or all):
  // 1- More suitable than console.log
  console.error(e);

  // 2- Notify user if applicable
  alertUserOfError(e);

  // 3- Report to server
  reportErrorToServer(e);

  // 4- Use a custom error handler
  throw new CustomError(e);
}

6. Annotations

Only comment business logic

Readable code saves you from over-commenting, therefore, 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 comments on historical versions in the code. If you want to check, you can just search using git log. .

// Don't ❌
/**
 * 2021-7-21: Fixed corner case
 * 2021-7-15: Improved performance
 * 2021-7-10: Handled mutliple user types
 */
function generateCanonicalLink(user) {
  // const session = getUserSession(user)
  const session = user.getSession();
  // ...
}

// Do ✅
function generateCanonicalLink(user) {
  const session = user.getSession();
  // ...
}

Ok, go write your beautiful code! 🌈

Summarize

This is the end of this article on how to write clean JavaScript code. For more information about writing clean JavaScript code, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • JS pop-up window code collection (detailed arrangement)
  • A detailed explanation of the authentic regular expression js code for verifying email addresses
  • JavaScript code to get the current timestamp
  • JS class encapsulation and implementation code
  • A very good JS paging effect code, worth studying
  • js code to realize the 60-second countdown when clicking the button
  • Determine whether a function or variable exists in JavaScript
  • Detailed explanation of variable promotion and function promotion in JavaScript

<<:  Complete steps to implement face recognition login in Ubuntu

>>:  MySQL 8.0 user and role management principles and usage details

Recommend

Detailed explanation of object literals in JS

Table of contents Preface 1. Set the prototype on...

Detailed explanation of the use of custom parameters in MySQL

MySQL variables include system variables and syst...

Simple usage of MySQL temporary tables

MySQL temporary tables are very useful when we ne...

Learn about TypeScript data types in one article

Table of contents Basic Types any type Arrays Tup...

Sharing tips on using scroll bars in HTML

Today, when we were learning about the Niu Nan new...

MySQL incremental backup and breakpoint recovery script example

Introduction Incremental backup means that after ...

What are HTML inline elements and block-level elements and their differences

I remember a question the interviewer asked durin...

A brief discussion of four commonly used storage engines in MySQL

Introduction to four commonly used MySQL engines ...

Detailed explanation of the use of MySQL mysqldump

1. Introduction to mysqldump mysqldump is a logic...

How to modify the time in centos virtual machine

The one above shows the system time, and the one ...

Sample code for implementing 3D rotation effect using pure CSS

Mainly use the preserve-3d and perspective proper...

Global call implementation of Vue2.x Picker on mobile terminal

Table of contents What is the Picker component Pr...

Tutorial on installing GreasyFork js script on mobile phone

Table of contents Preface 1. Iceraven Browser (Fi...

Steps to install RocketMQ instance on Linux

1. Install JDK 1.1 Check whether the current virt...