Clean up your code with destructors and Array.includes

Clean up your code with destructors and Array.includes

·

5 min read

Introduction

There are two things in JavaScript that I love using for cleaner code. And if you read the title, you can guess that those are destructors and includes function. In this post, I will give you a short overview of them and the use case where I use them.

1 r40RwbuUJjMCebiumccA9w.jpeg

Destructors

What is destructing? Destructing is the assignment syntax where it is possible to unpack values of arrays and objects. It is still not fully clear? Maybe it will be better with an example. Let’s take an example of the following simple object containing two properties:

const person = {
    firstName: 'John',
    lastName: 'Doe'
}

If we wanted to unpack properties in the old way, we would use dot or square brackets.

const firstName = person.firstName;
const lastName = person[“lastName”];

With the destructors, there is no need for either. We use curly brackets on the left side and names of the properties and the source object on right to unpack them.

const { firstName, lastName } = person;

You have to agree, much cleaner than either option above. Especially if you want to keep variable names the same as property names on the source object. There is more to this way of assignment. You can unpack them under an alias and use them on arrays. But that is not something I will go into in this post. You understand the idea.

Array.includes

This is a simple, built-in function of arrays where you pass one argument, the value you are looking for, and if the array contains it, returns true. Otherwise, returns false. The functionality was already possible in different ways. More complex one like looping array using for of forEach loops. Or simpler ones like using the find method or the indexOf method where any returned value equal to or larger than zero means array containing element. This way is just cleaner and more obvious.

const numbers = [1, 2, 3, 4];
numbers.includes(2); // true
numbers.includes(7); // false

Use case

Now we come to the real-life application of combining both the includes function and destructors. Let us say you have a situation where you are checking if the value of your variable is equal to either of your constants. And because you want to have cleaner code, you added all your constants under the same map.

const NAMESPAC = {
    VALUE_1: 'value 1',
    VALUE_2: 'value 2',
    VALUE_3: 'value 3',
    VALUE_4: 'value 4',
…
    VALUE_N: 'value N’,
}
const myVariable = 'value 3'

The first solution you could use for this is simple if statements:

if(myVariable === NAMESPACE.VALUE_1 || myVariable === NAMESPACE.VALUE_2) {
    // do something
} else if(myVariable === NAMESPACE.VALUE_3 || myVariable === NAMESPACE.VALUE_4) {
    // do something else
} else {
    // default action 
}

This can be ok, but what if you have long variable names and more of them in the same case? You end up with the if statement stretching over multiple lanes which are both difficult to read and easy to make a mistake. And then we get to the next possible solution. Did you notice how the first sentence of this paragraph contains a word case? If you did, you can guess it, a possible improvement used by many is switch-case. Especially when many add linting restrictions on how many ifs are allowed to be in a function. So let us look at this example.

switch(myVariable) {
case NAMESPACE.VALUE_1:
case NAMESPACE.VALUE_2:
    // do something
break;
case NAMESPACE.VALUE_3:
case NAMESPACE.VALUE_4:
    // do something else
break;
    default:
        // default action
}

This is quite a good solution. And hey, any solution that solves a problem, is a good solution. But for me, while used it a lot in the past, I am not a big fan of it anymore. Reason? I just don’t feel like it reads as naturally. That is why we come to the includes function.

    if([NAMESPACE.VALUE_1, NAMESPACE.VALUE_2].includes(myVariable)) {
        // do something
} else if ([NAMESPACE.VALUE_3, NAMESPACE.VALUE_4].includes(myVariable)) {
    // do something else
} else {
    // default action
}

Now this one is kind of like the first solution, but shorter and easier to read. Also, it can grow, and we can improve it even further. That is why this post also included destructors.

const { VALUE_1, VALUE_2, VALUE_3, VALUE_4 } = NAMESPACE;
if([VALUE_1, VALUE_2].includes(myVariable)) {
        // do something
} else if ([VALUE_3, VALUE_4].includes(myVariable)) {
    // do something else
} else {
    // default action
}

As you can see, much less code, and is easier to read. Someone might argue that there is a reason why constants were under a namespace. Conflicting names, better organization, and that is all true. But none of that is removed in your code. If you keep your functions clean, meaning small and aiming at pure functions, these unpacked values are visible in the small scope of your function and are only used so that you don’t need to constantly type the full category name.

Wrap-up

In this post, I am demonstrating the way I find code to look cleaner and to be easier to read. But that does not mean you should start writing this way. This is something that works for me, and if it works for you as well, great. But every problem has multiple solutions and it is up to you to choose the right one for your problem.


For more, you can follow me on Twitter, LinkedIn, GitHub, or Instagram.