Best Practices and Clean Code Tips for JavaScript Functions
JavaScript is a powerful programming language with many built-in functions and methods. Creating your own functions can make your code more modular, easier to read, and more reusable. However, when writing functions in JavaScript, it’s important to follow best practices and use clean code techniques to make your code more maintainable and efficient.
In this article, we’ll explore some of the best practices and clean code tips for writing functions in JavaScript.
Table of Contents
- Introduction
- Best Practices for Writing Clean Functions in JavaScript
- Keeping Functions Small and Focused
- Using Descriptive and Meaningful Names
- Properly Documenting Your Functions
- Avoiding Nesting Your Functions Too Deeply
- Using Default Parameters in Your Functions
- Clean Code Tips for Writing Functions in JavaScript
- Following Consistent Code Formatting
- Utilizing Arrow Functions
- Avoiding Side Effects in Your Functions
- Using Destructuring in Your Functions
- Avoiding Mutating Your Function Arguments
- Don’t use flags as function parameters
- Conclusion
Best Practices for Writing Clean Functions in JavaScript
Keeping Functions Small and Focused
One of the most important best practices to follow when writing functions in JavaScript is to keep them small and focused. A general rule of thumb is that functions should do only one thing and do it well. This makes your code more modular and easier to test, debug, and maintain.
This is bad:
function emailClients(clients) {
clients.forEach(client => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
But this is a good one:
function emailActiveClients(clients) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
Using Descriptive and Meaningful Names
Choosing descriptive and meaningful names for your functions and variables can make your code more readable and understandable. It’s important to choose names that accurately describe the purpose and behavior of your functions, avoiding abbreviations or acronyms that could be ambiguous.
Do not do this:
function addToDate(date, month) {
// ...
}
const date = new Date();
// It's hard to tell from the function name what is added
addToDate(date, 1);
Do this:
function addMonthToDate(month, date) {
// ...
}
const date = new Date();
addMonthToDate(1, date);
Properly Documenting Your Functions
Another best practice for writing clean functions in JavaScript is to properly document your functions. This can include writing comments that explain what the function does, what parameters it accepts, and what it returns. You can also use JSDoc annotations to generate documentation automatically.
/**
* The function filters active clients and sends them an email.
* @param clients - an array of client objects, where each object represents a client and contains
* information such as their name, email address, and whether they are an active client or not.
*/
function emailActiveClients(clients) {
clients.filter(isActiveClient).forEach(email);
}
/**
* The function checks if a given client is active in a database.
* @param client - The parameter "client" is a variable that represents the name or identifier of a
* client that we want to check if it is active or not.
* @returns The function `isActiveClient` is returning a boolean value indicating whether the client
* passed as an argument is active or not. The value is determined by calling the `isActive()` method
* on the client record retrieved from the database.
*/
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
Avoiding Nesting Your Functions Too Deeply
Nesting your functions too deeply can make your code harder to read and understand. As a best practice, try to keep your functions at a maximum nesting depth of two or three. If you need to nest functions more deeply, consider refactoring your code to split the functionality into smaller, more focused functions.
Don’t do this please:
var blah = function () {
var check = false;
verify({ success: function () {
if... check = true;
else... check = false;
}});
return check;
};
Using Default Parameters in Your Functions
Default parameters are a new feature in ES6 that can make your code more concise and expressive. Using default parameters can also make your functions more robust and less prone to errors since they can handle missing or undefined values more gracefully.
You can do like this:
function greet(name = "World") {
console.log(`Hello, ${name}!`);
}
greet(); // outputs "Hello, World!"
greet("John"); // outputs "Hello, John!"
Clean Code Tips for Writing Functions in JavaScript
Following Consistent Code Formatting
Consistent code formatting can make your code more readable and uniform, which can make it easier to understand and maintain. Follow a consistent style guide or convention, for example, Google’s JavaScript Style Guide or the AirBnb JavaScript Style Guide.
Utilizing Arrow Functions
Arrow functions are a new syntax in ES6 that can make your code more concise and expressive. They also have fewer context-related bugs than traditional function declarations. Consider using arrow functions for simple, anonymous functions, especially when working with arrays or callback functions.
See the beauty of arrow functions:
// Regular declaration
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
Avoiding Side Effects in Your Functions
Side effects occur when a function modifies the state of something outside of itself, which can cause unpredictable behavior and make your code hard to test and maintain. As a general rule of thumb, functions should be pure, meaning that they shouldn’t have any side effects.
This is not good:
Here global variable name is referenced by splitIntoFirstAndLastName function.
If we had another function that used this name, now it’d be an array and it could break it.
let name = "Kazim Kayhan";
function splitIntoFirstAndLastName() {
name = name.split(" ");
}
splitIntoFirstAndLastName();
console.log(name); // ['Kazim', 'Kayhan'];
Instead, you could do this:
function splitIntoFirstAndLastName(name) {
return name.split(" ");
}
const name = "Ryan McDermott";
const newName = splitIntoFirstAndLastName(name);
console.log(name); // 'Kazim Kayhan';
console.log(newName); // ['Kazim', 'Kayhan'];
Using Destructuring in Your Functions
Destructuring is a feature in ES6 that allows you to extract specific values from arrays or objects, which can make your code more concise and expressive. Using destructuring can also make it easier to read and understand what values your functions are working with.
This is not good:
function printEmployeeDetails({ name, age, jobTitle }) {
console.log(`Name: ${name}, Age: ${age}, Job Title: ${jobTitle}`);
}
But this one is good:
const employee = {
name: "John",
age: 30,
jobTitle: "Software Engineer"
};
printEmployeeDetails(employee);
Avoiding Mutating Your Function Arguments
When you pass an object or array into a function in JavaScript, any changes you make to the object or array will be reflected outside of the function. To avoid unintended side effects, it’s best practice to avoid mutating your function arguments. Instead, consider creating a new object or array to return from the function.
Don’t do this:
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
Do this:
const addItemToCart = (cart, item) => {
return [...cart, { item, date: Date.now() }];
};
Don’t use flags as function parameters
Flags are used to indicate to a user that a function is performing multiple operations. However, it is recommended that functions should only perform one task. Therefore, if a function is following different code paths based on a ‘true/false’ value, then it’s best to split the function into several functions that each perform a single task.
Bad example:
function createFile(name, temp) {
if (temp) {
fs.create(`./temp/${name}`);
} else {
fs.create(name);
}
}
Good example:
function createFile(name) {
fs.create(name);
}
function createTempFile(name) {
createFile(`./temp/${name}`);
}
Conclusion
In this article, we covered some of the best practices and clean code tips for writing functions in JavaScript. By following these guidelines, you can create more modular, maintainable, and efficient code. Remember to keep your functions small and focused, avoid global variables, and choose descriptive and meaningful names. Also, follow consistent code formatting, utilize arrow functions, avoid side effects, use destructuring, and avoid mutating your function arguments. By applying these best practices and clean code tips, you can take your JavaScript programming skills to the next level. If want to read more like this please check out my previous article about JavaScript Variable best practices.