5 Tips to Write Clean Code in Javascript
5 Tips to Write Clean Code in Javascript

In this post I want to share with you 5 more Javascript examples how you can make your code better and cleaner.

Don't use flags as function parameters

The first rule that I highly recommend you is to avoid flags as function parameters. As you can see here is a bad example.

// bad
function createFile(name, temp) {
  if (temp) {
    fs.create(`./temp/${name}`);
  } else {
    fs.create(name);
  }
}

The main problem here is that we create a file based on the boolean property that we passed. If temp is true we create a file in temporary directory. And temp property is not exactly some needed argument with some data. It is our flag to write some different logic inside a function. And it is always better when your function does just one thing.

This is why it's much better here to just create 2 different functions.

// good
const createFile = (name) => fs.create(name);
const createTempFile = (name) => createFile(`./temp/${name}`);

Here we made 2 separate functions. They are much easier to read, we can use them for separate cases and we don't have any flags inside.

Encapsulate conditionals

The next one is kind of obvious but people don't do it enough. So normally people just throw some conditionals inside an if. And it looks fine until you have 1 or 2 conditions. But actually even this single liner is difficult to read.

// bad
if (fsm.state === "fetching" && isEmpty(listNode)) {
  // ...
}

You really need to read every condition to understand the resulting logic. When we encapsulate logic inside additional variable it brings lots of clarity.

// good
const isSpinnerShown = fsm.state === "fetching" && isEmpty(listNode);

if (isSpinnerShown) {
  // ...
}

As you can see adding a variable changed a lot. Now we don't just read 2 conditions but see that actual goal of it. Checking if spinner is shown.

This is why I highly recommend you to always move your conditionals to additional variable if you have more than 2 of them.

Avoid negative conditionals

This one is extremely important. You must avoid negation at all costs. Because actually it is more difficult to read negation than just code.

// bad
function isDOMNodeNotPresent(node) {
  // ...
}

if (!isDOMNodeNotPresent(node)) {
  // ...
}

As you can see here we have a function which is written with negation. This is why when we use it we must put exclamation mark to check for DOM element. It is much better to always create variables and functions without negation.

// good
function isDOMNodePresent(node) {
  // ...
}

if (isDOMNodePresent(node)) {
  // ...
}

Here we removed not from our function and it is much easier to read. Even if we need negation later (like !isDOMNodePresent()) it will still be easier to read.

Don't override prototypes

The next one is super difficult to debug.

// bad
Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};

As you can see here we overrode a method inside array prototype. And actually typically more advanced developers do such stuff. They think that "Okay. I have an array. I just want to make a chain with my custom function". And actually it makes sense. In this case you can write.

arr.filter(user => user.isActive).diff(arr2)

So you can just call your custom diff function on any array. This is exactly why developers like to override prototypes inside arrays and objects.

But it is really dangerous because you can install some library which might do the same and also override prototype with such method. Or another developer will do the same. And then you have a name collision. This is why we need to leverage modular system like es6 modules or common js.

If you really need a custom reusable function just put it in additional module and export to reuse.

// good
export const diff = (arr, comparisonArray) => {
    const hash = new Set(comparisonArray);
    return arr.filter(elem => !hash.has(elem));
  }
}

And sure we can't use it directly on the array anymore. This is completely fine. This is how it is done in all popular libraries with helpers like Lodash or Ramda. This libraries never mutate prototypes. They create some different things to work with chains.

For example in libraries you can see such construction.

_.(arr).filter().diff()
R.compose(filter(), diff(), arr)

So we never mutate prototypes. We just use some wrappers from the libraries itself.

Bonus: Use method chaining

People don't use chaining in plain Javascript enough. And actually when we work with arrays it is really awesome. We can write code like this.

// good
const result = arr
  .filter(user => user.isActive)
  .sort((user1, user2) => user1.name < user2.name)
  .map(user => user.name)

Here we don't create additional variables and in every line we see how our data are being transformed.

Conclusion

I hope that this recommendations will improve your Javascript code. And if you want to see 5 more cases of clean Javascript make sure to check this post.