Javascript Clean Code
In this article, we will see 10 tips that will help you write clean javascript code in your day-to-day projects. I have to mention that the tips, we are going to look at are tips that have helped us personally. Hence, this article is slightly biased by my learnings on how to write cleaner code.
10 Ways To Write Clean JavaScript Code
You might feel differently about a few of the suggestions but overall I feel these 10 steps will definitely benefit you in your work or projects.
1. Avoid magic numbers
In programming, a magic number is a unique value with unexplained meaning. You would typically when working with if conditions, for loops, or even as part of schedulers and timers.
if(password.length < 8) {
//Display error message
}
So in the above example, instead of a “password.length < 8”, we will create a constant MIN_PASSWORD_LENGTH and use that constant as in the below.
const MIN_PASSWORD_LENGTH = 8
if(password.length < MIN_PASSWORD_LENGTH) {
//Display error message
}
By avoiding magic numbers your code is cleaner and much more readable and will benefit any developer who comes after you.
2. Avoid additional context
This is not a big deal, but it definitely improves the readability of your code. This point comes into play when naming object properties or methods.
Ex:
const employee = {
employeeName : 'john',
employeeAge : 26,
employeeSalary : 50000
}
In the code, we have created the object name is an employee, and the properties would be employeeName, employeeAge, and employeeSalary. In these cases, it is better to avoid duplicating the context for the property name. If the changed property name like just name, age, and salary, it will be much better when accessing properties like “employee.name, employment.age, employment.salary” than “employee.employeeName, employment.employeeAge, Employee.employeeSalary”. So, you should create the property name like below:
const employee = {
name : 'john',
age : 26,
salary : 50000
}
3. Use default arguments instead of short-circuiting
Short-circuiting was the way to go about handling default values for parameters before ES6. So, if we had a function calculate discount which accepts a discount parameter. It was very common to use the operator to assign a default value if a discount wasn’t passed in.
//All products receive 10% discount
function calculateDiscount(discount) {
const minDiscount = discount || 10
// ...Rest of the function
}
In the above code snippet, we can see that every product receives a 10% discount by default. However, this can lead to unexpected bugs. If 0 is passed in as the discount value, 100% would still be applied even if we intentionally want to ensure no discount is applied. The cleaner and correct approach is to use default arguments for the function like the below:
//All products receive 10% discount
function calculateDiscount(discount = 10) {
const minDiscount = discount
// ...Rest of the function
}
So, in the above code, we set the default argument value discount = 10 and we simply assigned the discount to minDiscount.
4. Restrict function arguments to 3
The number of arguments to pass to a function, but what I’ve seen is restrict the number of parameters you can pass to a function. By that, I don’t mean to pass all the data that your function might need instead the recommendation is to pass 2 parameters to a function. And if there are more than 2 parameters they should all be passed in as options objects. Now, this is an approach you might have seen when using a lot of other libraries. Let’s see an example:
Ex:
const options = {
duration : 4000,
style : {},
className : ' ',
icon : " ",
iconTheme : {
primary : '#000',
secondary : '#fff',
},
role:'status',
ariaLive: 'polite',
}
toast('Hello wolrd', options)
toast('Hello wolrd', duration, style, className, icon, iconTheme, role, ariaLive)
Here is an example of react toast notification library. The toast method accepts 1 argument and a 2nd argument is an object which in turn accepts a lot more options. So, instead of having to specify 8 different arguments, you can pass in two but the second argument can be an object that contains several properties. Generally, too many parameters are an indication that your function might be doing too much.
5. Function should do one thing
When the functions do more than one thing, they are harder to compose tests and reason about. If you isolate a function to one action, it can be easily refactored, and your code will be much cleaner.
For example,
function notifyUsers(users) {
users.forEach(user => {
const userRecord = database.lookup(user)
if(userRecord.isSubscribed()) {
notify(user)
}
})
}
Consider the scenario of sending notifications to a list of users based on actions in your application. So, you would have a notifyUser() function, which accepts an array of user IDs as an argument. Within the function though forEach user, we first fetch the complete userRecord and invoke a method on each user to check if they’re subscribed for push notification and then notify the user. It would be cleaner to separate this into two functions, like the below code:
function notifySubscribedUsers(users) {
users.filter(isSubscribedUsers).forEach(notify)
}
function isSubscribedUsers(user) {
const userRecord = database.lookup(user)
return userRecord.isSubscribed()
}
Here, we have split a function into two notifySubscribedUsers() function, which calls the notify function, and an isSubscribedUsers() function, which checks if a user is subscribed or not. And isSubscribedUsers() is also used to filter a list of users. Even though our code is doing the same thing as before and our functionnames are much more descriptive of what they do. The two functions are easier to maintain test and refactor if necessary.
6. Avoid boolean flags as parameters
When you pass in a flag variable to a function, it indicates that the function does more than one thing, which is a violation of tip 5.
Ex:
function getItemCost(itemCost, isMember){
const MEMBER_DISCOUNT = 0.30
const NORMAL_DISCOUNT = 0.10
if(isMember) {
cost = itemCost * (1 - MEMBER_DISCOUNT)
} else {
cost = itemCost * (1 - MEMBER_DISCOUNT)
}
return cost
}
In the above example function, where we need to calculate the cost of an item after applying a discount. So, the function getItemCost() receives the original itemCost as its first argument and it also receives isMember as its second argument. If the user is a member, they get a 30% discount if not they get a 10% discount. By using isMember in an if condition, we have branching and the function is now doing two things. That is, calculating the itemCost for the regular user as well as the member. The clean code in the javascript scenario is to split the function into two, like the below:
function getItemCost(itemCost){
const NORMAL_DISCOUNT = 0.10
cost = itemCost * (1- NORMAL_DISCOUNT)
return cost
}
function getItemCostForMember(itemCost) {
const MEMBER_DISCOUNT = 0.30
cost = itemCost * (1 - MEMBER_DISCOUNT)
return cost
}
Here, we can have a getItemCost function and a getItemCostForMember function. So, to ensure that functions do only things and there is no conditional branching within the function. So, try and avoid boolean flags as parameters.
7. Encapsulate conditionals
Especially, if the condition has several logical operators.
Ex:
if (status === "loading" && isEmpty(productList) {
//...Rest of the code
}
In the above code, it is very common to show a loading indicator when making API requests. And the general tendency is to have the condition directly as the if statement expression. Instead, the cleaner approach would be to encapsulate the condition into a function and call that function as part of the if statement expression, like the below example code:
function shouldDisplayLoader(status, productList) {]
return status === "loading" && isEmpty(productList);
{
if (shouldIdDisplayLoader(requestStatus, productList)) {
//... Rest of the code
}
So, we now have a shouldDisplayLoader() funciton, which encapsulates our if condition. And now if the statement calls the function passing in the appropriate arguments. Doing this, not only helps others who are trying to understand the code but it’ll helps you as well. Encapsulating the function into a descriptive function will help you in the long run.
8. Avoid contractions when naming
Finding a short descriptive name may be hard but please try to avoid the contraction and avoid contractions when naming variables or functions. Let’s see the example:
Ex:
const curColor = 'blue'
function sndNoif() {}
funciton onBtnClk() {}
See the example, you can see that the names don’t help in any way and decrease code readability. Almost all code editors now have very good intelligence and autocomplete, you simply shouldn’t have an excuse to use meaningful names. So, try and avoid contractions as much as possible. So, you should name the variables like the below code:
const currentColor = 'blue'
function sendNotification() {}
funciton onButtonClick() {}
9. Use a prefix when naming boolean variables
You should use a prefix when naming the boolean variables. For example:
const isLoggedIn = true
const isActiveUser = false
You can use the ‘is’ prefix when declaring variables, that describes a ‘characteristic’ as in the above code. But the “is” prefix isn’t sufficient for all boolean variables, so you can make use of the “has” prefix to describe whether a boolean variable possesses a certain value in the given below context.
const hasFoll0wers = true
const hasAllergies = false
The prefixes also make the code more readable when used with an if statement.
10. Use a verb when naming the function
If you can fix using a specific verb based on the type of functionality, the code automatically becomes cleaner and easier to understand. I recommend the following 7 verbs when dealing with the functions based on their actual functionality,
- get = Access data immediately. Ex: getFullName
- set = Set a value. Ex: setFullName
- reset = Reset a value. Ex:resetCount
- fetch = Get data after indeterminate time or async data. Ex: fetchProducts
- remove = Remove an element. Ex: removeItem
- delete = Erase permanently. Ex : deleteComment
- handle = Handle events. Ex: handleClickOutside
If you have these verbs probably documented in your project, it will helpful for every developer on the team. Just by reading the function name, they would be able to get an idea of what the function is doing.
Conclusion
My intention is to ensure, we all write the code better. Hopefully, these 10 tips or suggestions will help you write clean code in javascript. I recommend you get started with this list and improve as you gain more experience writing code.