10 Tips for Writing Clean and Efficient Javascript Code

clean and efficient code

Writing clean and efficient code is one of the best skills you can develop. That kind of code is easily maintainable, it scales easily and it’s fun to work with. Whatever language or framework you are using this skill will help you get a better job or build better projects.

Introduction

While choosing the topic for this week’s post, I was struggling. There are so many things that I would like to write about, but I decided to go with this one. And I will try to explain why in a single line below. Are you ready?! Here it goes

Code is like humor. When you have to explain it, it’s bad

Nobody likes lousy humor right? The same goes for code, even more, if I may add. Someone will blame the language, and someone will blame the framework, but in the end none of those things matters. Your code will be compiled to machine code all those ones and zeroes. You are writing the code for someone else not for the machine. Stick around and I’ll show you why.

Code this 🚀 not that 💩!

Well, I needed to tell you bluntly! I will try to give you a comparison for every example. Because there are people that are writing complex code on purpose, and unfortunately you’ll need to work with some of them throughout your carrier. I encourage you to choose your style and fight your own battles, don’t just follow the path make your own trail! Because in the end, that’s the most important thing for your career. Everybody can write the code, but only maintainable code survives. It’s really hard to upgrade the legacy application written in PHP 5, and it’s even harder when that code is written poorly! Now one piece of advice for me as well as you!

Talk is cheap. Show me the code.

Language

Always code in English! I can’t stress this enough guys, it’s so important. It doesn’t matter if you are a freelance coder or you are working in a multinational company, you need to keep other people in mind even when they are not doing the same for you. That’s where your greatness really shines!

class Serpa {
constructor() {
    this.brojDrski = 2;
    this.materijal = "celik";
    this.maxTemperatura = 300 + 'C';
}
}

And I haven’t even used the Serbian alphabet! Hahaha, it looks hilarious, doesn’t it? I mean even to me. You can’t send this to anyone and ask for help, I mean it’s not readable.

Naming things

Be explicit, don’t be shy, and make confusion. Speak your mind, but be concise. Don’t overdo it and make the variable too long.

// code this ✅
const createdAt = new Date();
// not that ❌
const ca = new Date();

The same goes for function names, try to describe what the function is doing in the name. So let’s take an example of the oven.

// code this ✅
function increaseHeat() {}
// not that ❌
function cookItFaster() {
}

How to use classes in Javascript?

Why, when, and how to use classes in JS. Well, why is pretty easy firstly you are organizing your code better, secondly you are taking advantage of the object-oriented principles, lastly you are genuinely writing more readable and scalable code.

class Vehicle {
    constructor() {
        this.doorCount = 4;
        this.wheelCount = 4;
    }

    shiftGear() {}

    increaseSpeed() {}

    brake() {}
}

You got all of that in one file, that you can extend! The next class that’s a motorcycle and change property. Motorcycles usually have two wheels, no doors, etc. But they can shift gears, increase speed, or brake, right? So you don’t need to write that code again and again for each type of Vehicle that you create in your code.

Use arrow functions

Use function what, now? ES6 has been here for a while now, if you are not using/learning those new features you are missing out, believe me. Arrow functions are really neat features to use for callbacks for example or for regular functions inside React components. You should write callbacks as arrow functions because they are not changing the scope, and it’s pretty useful for event listeners. Arrow functions are using that arrow syntax const myFn = () => {}.

  • myFn is a function name
  • arguments go to ()
  • function body goes to {}

Take a look at the example below, we are using a class that extends another class. And for the event listeners in the constructor, we are using the arrow function for a callback.

class Motorcycle extends Vehicle {
    constructor() {
        super();
        this.doorCount = 0;
        this.wheelCount = 2;

        this.speedUpBtn = document.getElementById("#speed-up-button");

        this.speedUpBtn.addEventListener((event) => {
            console.log(event); // ➡️ You have event like you would normally do
            console.log(this); // ➡️ points to the class Motorcycle

            fetch("flowers.jpg").then((response) => {
                console.log(event); // ➡️ Server response
                console.log(this); // ➡️ still points to the class Motorcycle
            });
        });
    }
}

Implicitly return

If you want your function to return something straight away without writing a function body. You can do that with arrow functions.

const allUpperCase = (someString) => someString.toUpperCase(); 

There you go one-liner for a simple task, and I would recommend you do this only for simple methods. Else you are going to get a very long spaghetti code, and that’s not tasty, not at all!

Object destructuring in JavaSript

If you are having a function that’s getting an object with a lot of props, you can destructure them right inside the argument parentheses. Let’s take a look at the example below.

// Don't do this 💩
const productCard = (product) => {
    const name = product.productName;
    const description = product.description;
    const price = product.price;
    const discount = product.discount;
};

// Do this instead 🤩
const productCardBetter = (product) => {
    const { productName, discount, description, price } = product;

    console.log(productName, discount, description, price);
};

productCardBetter({
  productName: "iPhone",
  discount: 0,
  price: 500,
  description: "This is a phone that...",
});

But there is a catch, right? The backend developer overnamed stuff so we ended up with a productName instead of just a name. If you don’t like that, it can be more simple because you only got products in this file or it’s a product class or it’s all just for fun. We can destructure an object and change the name on the fly:

const productCardBetter = (product) => {
    // const { name, discount, description, price } = product; // Don't give up! 😢
    const { productName: name, discount, description, price } = product; // JS got your back! 💪🏼
    console.log(name, discount, description, price);
};

productCardBetter({
  productName: "iPhone",
  discount: 0,
  price: 500,
  description: "This is a phone that...",
});

Don’t repeat yourself

As your mother probably told you when you were a kid. Don’t make me repeat myself. The same goes for the code. Just don’t do it, we are all on the clock and we need to finish our tasks fast. But sit a while and think how you can make that class, or method better. How can you make it once and then use it on multiple occasions?

When I am working on some legacy project, I usually deal with some bad js full of hacks and of course jQuery. And there are a lot of elements from the jquery UI for example.

Recently I had a project where we use tooltips to show additional information about suppliers. We are using that on four occasions throughout the application all on the different modules. Since we are not using the babel to compile our js I have created a new class in a file called tooltip.js. Firstly I have included that file like so:

<script src="/js/tooltips.js" type="module"></script>

Secondly, since it’s a module I can import that file wherever I want to. Lastly, I have created a class tooltip, that handles everything, from getting the element and showing the tooltip to the AJAX call that fetches the data.

In addition to the cleaner code I have a single-responsibility class, that’s rendering the tooltip on hover over any element that has a certain CSS class.

Control statements

Take control over your code. Don’t let bad code controls you! If you write bad code and come back to it a month after. You don’t know what the heck that code is doing and it’s full of temporary solutions and if else blocks. Don’t do that, use control (guards) statements like this.

const email = "asd@asd.com";
const password = "asdasd";

const validateUser = (email, password) => {
    if (!email) {
        throw new Error("Please, populate email field!");
    }

    if (!password) {
        throw new Error("Please, populate password field!");
    }

    if (!email.includes("@")) {
        throw new Error("Please, use a valid email!");
    }

    if (password.length < 6) {
        throw new Error("Please, use a strong password!");
    }
    return { email, password };
};

try {
    console.log(validateUser(email, password));
} catch (error) {
    console.error(error.message);
}

If we look at the code above it’s full of negativity, but you are gaining positivity through that. Because you have checked all the boxes that you need to validate the user before submitting the form you can return the user object and send a request to the backend. Of course, this is all hypothetical and validation of the email and password should be more strict, but it’s good enough for our small example here.

Imagine how awful this code would look if we used else for each case and then in the same function we submit the request etc. It would be too long and not maintainable. The next topic is related to this one so let’s continue this discussion there.

Trust the users not to do what they should do.

Error handling

Like in the previous section where we explored guard statements, we have also used throw to throw the Error like the one below.

throw new Error("Please, use a strong password!");

That forces us to call the function in the try catch block where we can try execute something and if it fails code in the catch block will run, where we can handle that error.

try {
    console.log(validateUser(email, password));
} catch (error) {
    console.error(error.message);
}

Here we can see that we are calling the function in the try block, and in the catch, we are catching the error. Where we can handle it, for example showing the message to the user or even logging this error message to a file, or sending an email to an admin user if something really bad happens. And I will finish this section with one of my favorite quotes.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Always use === for comparison

A triple equal sign means that we are comparing not only the value but also the type. Therefore we can be sure that this value is really what we are hoping for.

let a = "2";
let b = 2;

if (a == b) {
    console.log(a + b);
}

Look at the code above, what will be printed in the console? Since this is a really easy example I am sure most of you already know. But it’s going to print 22. Why? Because JS is a soft type language. So number 2 plus string 2 is 22 because JS is concatenating those two like both of them are the type of String, when they are not. How we can defend ourselves from this? We could parse the b variable to int or we can use triple equal to compare the type too instead of only comparing the value.

let a = "2";
let b = 2;

if (a === b) {
    console.log(a + b);
}

The above console.log won’t run at all. If that didn’t convince you, fine. It’s just fine. Checkout the examples below:

console.log("'0' == false", "0" == false); // true
console.log("[1,2,3] == '1,2,3'", [1, 2, 3] == "1,2,3"); // true
console.log("'\r\n\t' == 0", "\r\n\t" == 0); // true

Well if that’s not weird I don’t know what is. So if you don’t want to make your life living hell, please use === always!

Use default values for parameters

This one is really cool ES6 feature, when I told you up above that I created a class for my tooltip element, well default operators helped me a lot. Because I wanted my tooltip to always show under the element that you are hovering over. But I’ve found some strange cases where I have a bunch of data in the tooltip and it’s covering a good chunk of some table below. Then I set a new parameter like constructor (... position = 'bottom') {} and only for that one case I would create a new instance and send a position parameter as right, in all the other cases I am not sending anything for the position, the default will be used.

class Motorcycle extends Vehicle {
    constructor(mark, wheels = 2) {
        super();
        this.mark = mark;
        this.wheelCount = wheels;
        this.doorCount = 0;
    }
}

console.log(new Motorcycle("Yamaha")); // will print Motorcycle { doorCount: 0, wheelCount: 2, mark: 'Yamaha' }
console.log(new Motorcycle("BMW", 3)); // will print Motorcycle { doorCount: 0, wheelCount: 3, mark: 'BMW' }

So in this example, you can see it plain and clear. For the Yamaha, we have omitted the wheels, because there is no point because it has 2 wheels and that’s our default value. But for BMW we have placed it to be three because there is that weird-looking scooter with one wheel at the front and to in the back.

How to use object destructuring and the default values?

You got it chief! It’s pretty easy, just use an equal sign like the one in the code below, and you are all set!

class Motorcycle extends Vehicle {
    constructor({ mark, wheels = 2 }) {
        super();
        this.mark = mark;
        this.wheelCount = wheels;
        this.doorCount = 0;
    }
}

console.log(new Motorcycle({ mark: "Yamaha" }));
 // will print Motorcycle { doorCount: 0, wheelCount: 2, mark: 'Yamaha' }

console.log(new Motorcycle({ mark: "BMW", wheels: 3 }));
 // will print console.log(new Motorcycle({ mark: "BMW", wheels: 3 }));

Heads up! Javascript fights back!

If we change the console.log for Yamaha to console.log(new Motorcycle({ mark: "Yamaha", wheels: null})); wheelsCount will be null. The default value kicks in only when the value we are sending is undefined!

Conclusion

Well, I don’t need to say that conclusion is easily readable here. Write clean code, that’s all there is. You might be more frustrated in the beginning, you might even take more time to finish the work, etc. But in the end, you will be grateful to yourself for doing that. When you are back on the project for a framework update for example and you see the clean classes or components, you just smile don’t say anything, and be proud of yourself! Because that update or any additional feature development is going to be finished in no time!

Always bet on JavaScript!
What’s your Reaction?
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top