Clean Code in JavaScript: Best Practices for Readable and Maintainable Code

Aquib Afzal
Bits and Pieces
Published in
8 min readApr 16, 2023

--

Photo by Tushar Gidwani on Unsplash

Clean code refers to code that is easy to comprehend, read, and maintain. It follows a set of principles and best practices that simplify the process of modifying and working with the code over time. Writing clean code is crucial as it promotes better software development practices, reduces the likelihood of bugs, and enhances the code’s ease of maintenance.

To create clean code in JavaScript, the following 10 things should be prioritized:

1. Use meaningful names

In order to write clean code, it’s crucial to use meaningful and descriptive names for variables and functions. This helps to convey the purpose and usage of these elements and makes the code more understandable and maintainable.

For example, consider the following code:

// Bad
let a = 10;
function f(x) {
return x + a;
}

// Good
let initialCount = 10;
function calculateFinalCount(currentCount) {
return currentCount + initialCount;
}

In the "bad" example, the variable a and the function f do not provide any clear indication of their purpose. On the other hand, the "good" example uses more descriptive names like initialCount and calculateFinalCount, which makes it easier to understand what they are used for.

When naming variables that store arrays, it's a good practice to use plural names to indicate that the variable stores multiple values. For instance, the following code is a good example:

// bad

let name = ["John", "Doe", "Peterson"]

// good

let names = ["John", "Doe", "Peterson"]

In the above example, names is a more descriptive name than name as it indicates that the variable stores multiple names.

When storing a Boolean value, it’s a good practice to use a prefix is in the variable name. For example, consider the following code:

// Bad

let loading = true

// Good

let isLoading = true

In the above example, using the prefix is in the variable name makes it easier to understand that it stores a Boolean value, and also makes it more descriptive.

2. Use naming conventions using camelCase

Using camelCase notation for naming variables, functions, objects, etc. is an important convention to make your code more readable and consistent. In camelCase notation, the first word is lowercase, and subsequent words are capitalized.

Here is an example:

//bad code

const personname = "John Doe"

//good code

const personName = "John Doe"

In the “bad” example, the variable personname is written in all lowercase, which makes it harder to read and understand. On the other hand, in the "good" example, the variable personName uses camel-case notation, which makes it easier to read and understand.

3. Indent code

Use code indentation tools like Prettier to keep the code clean and easy to read. This ensures that your code is consistently formatted and follows best practices, especially when dealing with complex nested structures. for code indentation, VS code extension (prettier) can be used.

// Before formatting with Prettier
function calculateArea(radius){
let area=3.14*radius*radius;
return area;
}

// After formatting with Prettier
function calculateArea(radius) {
let area = 3.14 * radius * radius;
return area;
}

4. Use Template Literals

Template literals are a more flexible and convenient way to work with strings in JavaScript. They allow you to embed variables and expressions directly inside a string, using special syntax with backticks (` `) instead of quotes (' ' or " ").

For example:

// Without using template literals
const name = "John";
const age = 30;

const message = "My name is " + name + " and I am " + age + " years old.";

console.log(message);
// Output: My name is John and I am 30 years old.


// Using template literals
const name = "John";
const age = 30;

const message = `My name is ${name} and I am ${age} years old.`;

console.log(message);
// Output: My name is John and I am 30 years old.

In this code, the string is constructed using concatenation with the + operator to combine the string and variables. While this approach works, it can be more cumbersome and harder to read, especially when dealing with longer strings and multiple variables.

However, the string is created using a template literal, which starts and ends with backticks (``). variables name and age are then embedded inside the string using the syntax ${variable}. This makes it much easier to read and write, especially when dealing with longer strings or multiple variables.

5. Use Functions for Splitting Code

Write functions for every specific task. Functions can help to split your code into smaller, more manageable chunks. This can improve readability, maintainability, and reusability. Functions should be focused on a specific task and should be named accordingly.

For example:

// Without using functions
let numbers = [1, 2, 3, 4, 5];
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
console.log(sum);

// Using functions
function calculateSum(numbers) {
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
return sum;
}
let numbers = [1, 2, 3, 4, 5];
console.log(calculateSum(numbers));

In the above example, the “calculateSum” function can be used many times when sum of numbers are needed. It makes the code more readable and reusable.

6. Send Arguments as Object

If you have to send multiple arguments then sending arguments as object can make your code more readable and flexible. Objects can contain multiple properties that represent different values, making it easier to understand the purpose and functionality of your code.

For example:

// Without using objects
function createUser(name, email, age) {
// ...
}

createUser("John Doe", "johndoe@example.com", 30);

// Using objects
function createUser(user) {
// ...
}

createUser({
name: "John Doe",
email: "johndoe@example.com",
age: 30,
});

8. Use Arrow Functions

Arrow functions are a concise way of writing functions in JavaScript. They can make your code more readable and reduce the amount of boilerplate code. Arrow functions have a simplified syntax and an implicit return statement.

For example:

// Without using arrow functions
let numbers = [1, 2, 3, 4, 5];
let evenNumbers = numbers.filter(function (number) {
return number % 2 === 0;
});
console.log(evenNumbers);

// Using arrow functions
let numbers = [1, 2, 3, 4, 5];
let evenNumbers = numbers.filter((number) => number % 2 === 0);
console.log(evenNumbers);

9. Conditional Execution with && Operator

In JavaScript, the && operator can be used to perform a conditional check and execute a second command only if the first value is truthy. ‘

For example:

// Example 1
let x = 5;
let y = "";

// Check if x is truthy, then execute the second command
x && console.log("x is truthy"); // Output: "x is truthy"

// Check if y is truthy, then execute the second command
y && console.log("y is truthy"); // No Output

In the example above, we have two variables x and y. The x && console.log("x is truthy") statement checks if x is truthy (i.e., not null, undefined, false, 0, NaN, or an empty string), and if it is, it executes the second command console.log("x is truthy"). Since x is not null, undefined, or 0, the second command is executed and the output "x is truthy" is printed.

On the other hand, the statement y && console.log("y is truthy") checks if y is truthy. Since y is “” (a falsy value), the second command is not executed and that’swhy there is not output.

10. Conditional Execution with || Operator

The || operator can be used to perform a conditional check and execute a second command only if the first value is falsy.

For Example:

let x = null;
let y = "Hello";

// Check if x is falsy, then execute the second command
x || console.log("x is falsy"); // Output: "x is falsy"

// Check if y is falsy, then execute the second command
y || console.log("y is falsy"); // No output

In the example above, we have two variables x and y. The x || console.log("x is falsy") statement checks if x is falsy (i.e., null, undefined, false, 0, NaN, or an empty string), and if it is, it executes the second command console.log("x is falsy"). Since x is null, which is a falsy value, the second command is executed and the output "x is falsy" is printed.

On the other hand, the statement y || console.log("y is falsy") checks if y is falsy. Since y is a non-empty string, which is a truthy value, the condition is falsy, and the second command is not executed, resulting in no output.

Here’s another example with a slightly different scenario:

let isLoggedIn = false;
let defaultUsername = "Guest";

// Check if isLoggedIn is falsy, then assign defaultUsername as the username
let username = isLoggedIn || defaultUsername;

console.log(username); // Output: "Guest"

In this example, we have a isLoggedIn and a defaultUsername variable. The isLoggedIn || defaultUsername expression checks if isLoggedIn is falsy. Since isLoggedIn is false, which is a falsy value, the expression evaluates to defaultUsername, and the value "Guest" is assigned to the username variable.

Using || in this way can provide a concise and efficient way to conditionally assign a default value or execute a second command based on the falsiness of a value. It's important to understand that the second command or default value will only be executed or assigned if the first value is falsy.

Build Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--

Software Developer @ Encora Inc. | Blogger | talks about #javascript #react #nodejs #performance #webdevelopment