14 tips to write better Javascript
Tags: javascript
Published: 2023-12-12 01:56:23

---
title: 14 tips to write better Javascript
published: true
tags: Javascript
canonical_url: https://blog.melvinvmegen.com/posts/javascript/14_tips_to_write_better_javascript
---

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jcw7vsay4hylzf5eb62.png)

Here are some of my favorite tips for writing cleaner Javascript code, skip the clever keep it simple.

## 1. Forget about var

Declare all your variables with either **const** or **let**. As a rule of thumb, use **const** by default otherwise if a variable needs to be reassigned use **let**. 

The **var** keyword should be avoided as it is almost scope free leading to potential scoping bugs, refer to my guide on [hoisting](https://blog.melvinvmegen.com/posts/javascript/hoisting).

**Bonus:** it’s best practice to initialize your variables at the time of creation so you and your team can ensure none are left unused.

```js
// ❌ Avoid this
var old = "";

// ✅ Do this
const immutable = "John";
let counter = 1;
counter++; // counter === 2;

// Declare objects and arrays as const to prevent type change
const user = {firstname: "John", lastname: "Doe"};
const users = ["Mac", "Roe"];
```


## 2. Be strict about equality

The strict equality operator [(===)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) same as the equality operator checks whether its two operands are equal, returning a Boolean result. But unlike the equality operator ([==)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality), the strict equality operator [(===)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) always considers operands of different types to be different.

**Bonus:** 0 being falsy will be wrongly equal to false in case of non strict equality operator.

```js
// ❌ Avoid this
1 == "1"; // true
0 == false; // true

// ✅ Do this
1 === 1; // true
1 === "1"; // false
0 === false; // false
```


## 3. Avoid constructors for primitive values

Primitive objects are strictly different than their primitive counterparts making
them harder to check for strict equality as they're wrapped in a object. 

They're are basically equivalent but not equal.

```js
// ❌ Avoid this
const stringObject = new String("Charly");

// ✅ Do this
const stringPrimitive = "Charly";

// Equality check
stringPrimitive === stringObject; // false 
new Number(1) === 1; // false
new Boolean(true) === true; // false
```


## 4. Make use of Object Literals

**Object literals** are a shorthand notation allowing you to define an object or an array on the fly. 

Thereby avoiding repetition, improving readability and preventing mistakes as we can't infer logic behind it, are we currently initializing a variable or updating it?

```js
// ❌ Avoid this
const user = new Object(); // {}
user.firstname = "John"; // { firstname: "John" }
user.lastname = "Doe"; // { firstname: "John", lastname: "Doe" }

// ✅ Do this
const user = { 
  firstname: "John", 
  lastname: "Doe" 
};

// ❌ Avoid this
const fruits = new Array(); // []
fruits.push("banana"); // ["banana"]
fruits.push("mango"); // ["banana", "mango"]

// ✅ Do this
const fruits = ["banana", "mango"];
```


## 5. Use template literals to combine strings

Putting strings together is a pain, especially when combining strings and variables. 

To make this process simpler, you can use [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (marked by backticks), which take both **strings** and **variables** as long as it is surrounded by the interpolation **(${})**.

```js
const firstname = "John";

// ❌ Avoid this
let greeting = "Hello, " + firstname; // Hello, John

// ✅ Do this
greeting = `Hello, ${firstname}`; // Hello, John
```


## 6. Use Semicolons for line termination

The use of semi-colons for line termination is always a good practice. 

You won’t be warned if you forget it, because in most cases it will be inserted by the JavaScript parser. But without it how would you know when an expression ends?

Take the for loop as an example :

```js
// ✅ Do this
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i]);
}
```

You wouldn't be able to do the following because to parser thinks it is one expression while it truly is three separate ones:

```js
// ❌ Not this
for (let i = 0 i < numbers.length i++) {
  console.log(numbers[i]);
} // Uncaught SyntaxError: Unexpected identifier
```


## 7. Use object param instead of multiple params

I consider it a **code smell** to define too many parameters in my functions. Even if parameters have default value or are optional, let's take this example:

```js
// ❌ Avoid this
function avatarUrl(avatar, format = "small", caption = true) {
  // Does something
}

avatarUrl(user.avatar, 'thumb', false)
```

When you use this function it's very hard to know which parameters are used and how. What does the last param **false**, stand for here?

No idea, we have to open the function definition in order to know.
And what happens if you need to change the parameter's order? Well you'll have to change all function calls.

With an object, order doesn't matter:

```js
// ✅ Do this
function avatarUrl(avatar, options={format: 'small', caption: true}) {
  // Does something
}

avatarUrl(user.avatar, {
  format: "thumb", 
  caption: false
})
```


## 8. Return as soon as possible
Nested conditions make it hard to understand code but you can easily avoid it with [guard clauses](https://en.wikipedia.org/wiki/Guard_%28computer_science%29), by returning early.

[Guard clauses](https://en.wikipedia.org/wiki/Guard_%28computer_science%29) will allow you to remove most of your else conditions making your code readable **like plain English**.

```js
// ❌ Avoid this
function doSomething() {
  if (user) {
    if (user.role === "ADMIN") {
      return 'Administrator';
    } else {
      return 'User';
    }
  } else {
    return 'Anonymous';
  }
}

// ✅ Do this
function doSomething() {
  if (!user) return 'Anonymous'
  if (user.role === "ADMIN") return 'Administrator'

  return 'User'
}
```


## 9. Learn and use the power of your tools
Javascript provides a lot built-in function on **Array**, **Object**, **String**.

Find and learn them to enjoy the full power of your stack.

```js
// ❌ Avoid this
const users = [
  {
    username: "JohnDoe",
    admin: false
  },
  {
    username: "Todd",
    admin: true
  },
];
const admins = [];

function getAdmins() {
  users.forEach((user) => {
    if (user.admin) admins.push(user)
  })

  return admins
}

// ✅ Do this
function getAdmins() {
  return users.filter((user) => user.admin)
}
```


## 10. Code for humans, not for computers

Let's assume it, most of us are bad at noticing differences, it might take us a few seconds before noticing a [logical not (!)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT).

Let's take this example:

```js
const users = [
  {
    username: "JohnDoe",
    admin: false
    enabled: true
  },
  {
    username: "Todd",
    admin: true
    enabled: true
  },
];

// ❌ Avoid this
const members = users.filter(u => u.enabled).map(u => !u.admin)
const admins = users.filter(u => u.enabled).map(u => u.admin)

// ✅ Do this
const enabledUsers = users.filter(u => u.enabled)
const members = enabledUsers.map(u => !u.admin)
const admins = enabledUsers.map(u => u.admin)
```

Both **members** and **admins** assignments only differ by the [logical not (!)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) and if you need to change one assignment, then you also need to change the other one.

Another example, do not use magic numbers. Use explicit variables instead:

```js
// ❌ Avoid this
function price_with_taxes(price) {
  return price * 1.2
}

// ✅ Do this
const taxRate = 1.2
function price_with_taxes(price) {
  return price * taxRate
}
```


## 11. Avoid abbreviations
Whether you write *e* for event, *t* for ticket won't boost your productivity but it does worsen readibility and decreases instant comprehension.

```js
// ❌ Avoid this
function someFunction() {
  events.forEach(e => {
    e.tickets.forEach(t => {
      `${e.name} for ${t.full_name}`
    })
  })
}

// ✅ Do this
function someFunction() {
  events.forEach(event => {
    event.tickets.forEach(ticket => {
      `${event.name} for ${ticket.full_name}`
    })
  })
}
```
Here you don't have to guess what e and t stand for, you just read it.
Coding is complex enough to bloat your mind with extra complexities. This also applies to variables, class, methods...

**There are few exceptions though, it's ok to use widely used abbreviations like i in your for-loops.**


## 12. Avoid useless && negated conditions  
Conditions are like memos for your brain as you need to remember them while stepping through each line of code in order to understand what's going on.

Fortunately, most of them can be simplified thanks to my favorite ES6 operator [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining).

```js
// ❌ Avoid this
function doSomething(params) {
  if (params && params.filter) return 'Foo'

  return 'Bar'
}

// ✅ Do this
function doSomething(params) {
  if (params?.filter) return 'Foo'

  return 'Bar'
}
```

I don't know about you but every time i see a [logical not (!)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) it makes my brain pause for a second, to me it feels more natural to read something like: 

*if a user IS an admin then we do that*

rather than: 

*if a user IS NOT an admin then we do that.*

```js
// ❌ Avoid this
function doSomething(user) {
  if (!user || !user.admin) {
    // Case where no user or not admin
  } else {
    // Case where user and user is admin
  }
}

// ✅ Do this
function doSomething(user) {
  if (user && user.admin) {
    // Case where user and user is admin
  } else {
    // Case where no user or not admin
  }
}
```


## 13. Use for...of instead of for loops
Using the **for...of** statement instead of the classical **for loop** is such a JavaScript improvement. 

This syntax has been introduced by ES6, and it includes a built-in iterator so that you don’t have to define your own variable, increment it until a certain length value:

```js
let users = ["Fedor Emelianenko", "Cyril Gane", "Conor McGregor"];

// ❌ Avoid this
// This avoids length behind reavaluated at every iteration
let usersCount = users.length;
for (let i = 0; i < usersCount; i++) {
	console.log(users[i]);
}

// ✅ Do this
for(let user of users) {
  console.log(user);
}
```

Notice how much more readable it is! And you don't have to care about all this (let i = 0; i < usersCount; i++) clumsy logic though you might need it for some specific use case, like an irregular interval.


## 14. Readable code outshines clever code
Always remember, you're writing code with other developers aswell as your future self. You don't want to create more problems than the ones you're solving writing code.

Don't write code to show off your skills, write code everyone can understand and debug.

If you have more tips, i'd be happy to learn them from you in the comments!

Keep it simple!