DEV Community

Cover image for 6 JavaScript Pro Tips That Will Make Your Code More Elegant and Maintainable πŸ”₯πŸ”₯πŸ”₯
Vergil
Vergil

Posted on

6 JavaScript Pro Tips That Will Make Your Code More Elegant and Maintainable πŸ”₯πŸ”₯πŸ”₯

As front-end development engineer, we can often enhance code readability and make our code look more elegant by paying attention to some small details in our work.

This time, I will share some handy and elegant JavaScript tips that are easy to grasp at first glance.

These tips aim to improve the efficiency and readability of your code.

Image description

Technique 1: Reducing if...else Spaghetti Code

When we find ourselves writing functions with more than two if...else statements, it's time to consider whether there are better optimization methods.

function getPrice(item) {
    if (item === 'apple') return 1.0;
    else if (item === 'banana') return 0.5;
    else if (item === 'orange') return 0.75;
    // more conditions...
}
Enter fullscreen mode Exit fullscreen mode

This kind of implementation can clutter the function body with many conditional statements. So, when we want to add another item, we would otherwise need to modify the logic inside the function to include another if...else statement.

This would, to some extent, violate the Open/Closed Principle (OCP). According to the OCP, when we need to extend a functionality, we should aim to achieve the requirement changes by extending software entities, rather than modifying the existing code.

This is a classic optimization strategy. We can use a data structure similar to Map to store all items. Here, we can directly create an object to store the data.

const priceMap = {
    apple: 1.0,
    banana: 0.5,
    orange: 0.75,
    // more items...
};

function getPrice(item) {
    return priceMap[item] || 0; // returns 0 if item not found
}
Enter fullscreen mode Exit fullscreen mode

This approach ensures that when we need to add another item, we don't have to alter the core logic of a function like getPrice.

Indeed, many prefer using something like foodMap directly where it's needed. Here, I’m just using a simple example to illustrate this thought process.

const priceMap = new Map();
priceMap.set('apple', 1.0);
priceMap.set('banana', 0.5);
priceMap.set('orange', 0.75);

function getPrice(item) {
    return priceMap.get(item) || 0; // returns 0 if item not found
}
Enter fullscreen mode Exit fullscreen mode

Technique 2: Using Pipelining Operations to Replace Redundant Loops

const foods = [
    { name: 'Apple', group: 1 },
    { name: 'Banana', group: 2 },
    { name: 'Carrot', group: 1 },
    // more items...
];

const group1Foods = [];
for (let i = 0; i < foods.length; i++) {
    if (foods[i].group === 1) {
        group1Foods.push(foods[i].name);
    }
}
Enter fullscreen mode Exit fullscreen mode

Traditionally, you might use a for loop to iterate over the array, checking each item for its group, and then accumulating the results.

While this method works, it can lead to verbose and less readable code. By using methods like filter and map, you can not only make the code more concise but also enhance its semantic clarity.

This way, it's immediately clear that the process involves first filtering the array and then restructuring it.

const group1Foods = foods
    .filter(food => food.group === 1)
    .map(food => food.name);

Enter fullscreen mode Exit fullscreen mode

Technique 3: Using find to Replace Redundant Loops

Continuing with the example above, if we want to search for a specific food in the array of food objects based on a property value, the utility of find becomes apparent.

Example:
Instead of using a for loop to search for a specific item:

const foods = [
    { name: 'Apple', group: 1 },
    { name: 'Banana', group: 2 },
    { name: 'Carrot', group: 1 },
    // more items...
];

let foundFood;
for (let i = 0; i < foods.length; i++) {
    if (foods[i].name === 'Banana') {
        foundFood = foods[i];
        break;
    }
}
Enter fullscreen mode Exit fullscreen mode

You can simply use find:

const foundFood = foods.find(food => food.name === 'Banana');
Enter fullscreen mode Exit fullscreen mode

The find method allows you to quickly locate the first element in an array that satisfies a provided testing function, offering a cleaner and more efficient alternative to traditional loops.

Technique 4: Using includes to Replace Redundant Loops

When you need to check whether an array contains a specific value, using the includes method can simplify your code significantly. Instead of iterating through the array with a loop to check for the existence of an element, includes provides a more efficient and readable way to achieve the same result.

Example:

Instead of using a for loop to determine if an array contains a certain element:

const fruits = ['Apple', 'Banana', 'Carrot'];
let hasBanana = false;
for (let i = 0; i < fruits.length; i++) {
    if (fruits[i] === 'Banana') {
        hasBanana = true;
        break;
    }
}
Enter fullscreen mode Exit fullscreen mode

You can simply use includes:

const hasBanana = fruits.includes('Banana');
Enter fullscreen mode Exit fullscreen mode

Using includes not only reduces the amount of code but also makes your intention clearer: checking for the presence of a value in an array.

This method offers an elegant solution to what could otherwise be a more verbose process using traditional loops.

It's especially useful when dealing with arrays where you frequently need to perform membership tests, helping you to write cleaner and more maintainable code.

Technique 5: Using a Consistent result Return Variable

As a best practice, especially in smaller functions, you can use a consistent variable name like result for the return value. This makes it clear where the return value is coming from, and it provides a standardized naming convention that you and others can easily recognize.

function calculateTotal(items) {
    let result = 0;
    for (let i = 0; i < items.length; i++) {
        result += items[i].price;
    }
    return result;
}
Enter fullscreen mode Exit fullscreen mode

Technique 6: Maintaining Object Integrity

When processing data returned from a back-end request, we often handle specific attributes individually. This is especially common when only a few properties need processing. Many developers tend to extract only the necessary attributes for operations, which is the first method.However, this practice can be impractical in the long run.

When it's uncertain whether a function will need additional dependencies later, maintaining the integrity of the entire object is advisable. For instance, if the function getDocDetail uses properties like icon and content now, there might be requirements for title, date, and other attributes in the future. Passing the complete object, rather than individual properties, not only reduces the length of the parameter list but also enhances the code's readability and flexibility.

Example:

Instead of extracting and passing only needed attributes:

function getDocDetail(icon, content) {
    // process icon and content
}

const doc = { icon: 'icon.png', content: 'Some content', title: 'Document Title', date: '2023-10-15' };
getDocDetail(doc.icon, doc.content);
Enter fullscreen mode Exit fullscreen mode

It's better to pass the entire object:

function getDocDetail(doc) {
    const { icon, content } = doc;
    // process icon and content
    // Access doc.title, doc.date etc. if needed in future
}

const doc = { icon: 'icon.png', content: 'Some content', title: 'Document Title', date: '2023-10-15' };
getDocDetail(doc);
Enter fullscreen mode Exit fullscreen mode

This approach future-proofs your function by allowing easy access to any additional properties without changing its signature. The code becomes more robust and easier to maintain as new requirements emerge, as it avoids the need to continuously alter function parameters. This practice supports modular design principles and contributes to cleaner, scalable codebases.

🌟 Final Thoughts

The JavaScript techniques shared above can effectively enhance code quality and stability. By implementing these strategies, such as reducing redundant loops, maintaining object integrity, and using modern JavaScript methods like filter, map, find, and includes, you can create cleaner, more efficient, and maintainable code. These practices not only simplify your coding process but also align with best practices, making your applications more robust and adaptable to change.

So, give these tips a try in your next project and experience the improvements first-hand. Happy coding!

Top comments (7)

Collapse
 
daniel_jones profile image
Daniel Jones

Thanks for sharing!

Collapse
 
geekvergil profile image
Vergil

Keep going

Collapse
 
declan_chiu profile image
Declan Chiu (declanchiu)

Perfect for a beginner like me.

Collapse
 
abhivyaktii profile image
Abhinav

Intresting read

Collapse
 
harleendance profile image
Hiram Kobbe

This expression uses more advanced vocabulary and phrases to convey a deeper sense of appreciation and admiration for the code shared.

Collapse
 
_1402b4d74b1aa41e425 profile image
ε˜Ώε˜Ώε“ˆε“ˆε“ˆ

so good

Collapse
 
cde97 profile image
cde-97

Elegantly Code