Top 10 Mistakes in JavaScript and How to Avoid Them (With Examples)

JavaScript is one of the most widely used programming languages, powering everything from simple web pages to advanced applications. However, even experienced developers frequently make common mistakes that lead to bugs, performance issues, and security vulnerabilities.

In this comprehensive guide, we will explore 10 common JavaScript mistakes, explain why they happen, and show you how to fix them with real-world examples.

Let's dive in! 🎯

1️⃣ Using var Instead of let and const

Problem: The var keyword has function-scoped behavior that can cause unexpected issues due to hoisting.

Bad Code (Using var)

function example() {
    if (true) {
        var name = "John";
    }
    console.log(name); // No error, but this can be dangerous
}

🔴 Issue: var does not have block scope, meaning name is accessible outside the if block.

Good Code (Using let and const)

function example() {
    if (true) {
        let name = "John";
        console.log(name); // ✅ Works fine
    }
    console.log(name); // ❌ ReferenceError: name is not defined
}

Why is this better?
let and const have block scope, preventing accidental overwrites.
const should be used for values that never change.

2️⃣ Forgetting === Instead of ==

Problem: JavaScript allows loose comparison (==), which can lead to unexpected type coercion.

Bad Code (Using ==)

console.log(0 == "0"); // true 😱
console.log(false == ""); // true 🤯

🔴 Issue: JavaScript automatically converts types, leading to unpredictable results.

Good Code (Using ===)

console.log(0 === "0"); // false ✅
console.log(false === ""); // false ✅

Why is this better?
=== ensures both type and value match.
✔ Avoids unexpected type conversions.

3️⃣ Not Handling Asynchronous Code Properly

Problem: Using synchronous code where asynchronous handling is required can cause issues.

Bad Code (Forgetting await)

async function fetchData() {
    let data = fetch("https://api.example.com/data");
    console.log(data); // ❌ Returns a Promise, not data
}

🔴 Issue: fetch() is asynchronous, so it returns a Promise, not the actual data.

Good Code (Using await)

async function fetchData() {
    let response = await fetch("https://api.example.com/data");
    let data = await response.json();
    console.log(data); // ✅ Now we get actual data
}

Why is this better?
✔ Ensures data is properly fetched before proceeding.
✔ Prevents Promise-related bugs.

4️⃣ Modifying an Object While Iterating Over It

Problem: Modifying an object or array during iteration leads to unexpected behavior.

Bad Code (Modifying While Iterating)

let users = [{ id: 1 }, { id: 2 }, { id: 3 }];
users.forEach((user, index) => {
    if (user.id === 2) {
        users.splice(index, 1); // ❌ Dangerous operation
    }
});
console.log(users); // Unpredictable results

🔴 Issue: The loop is still running while modifying the array, leading to skipped elements.

Good Code (Filtering Instead)

users = users.filter(user => user.id !== 2);
console.log(users); // ✅ Correctly removes item without issues

Why is this better?
✔ Prevents looping issues.
✔ Makes the code easier to read and maintain.

5️⃣ Using parseInt() Without a Radix

Problem: parseInt() can interpret numbers in unexpected bases if no radix is provided.

Bad Code (No Radix)

console.log(parseInt("08")); // ❌ Returns 0 in some browsers

🔴 Issue: Some versions of JavaScript assume octal (base 8) for numbers starting with 0.

Good Code (Always Specify a Radix)

console.log(parseInt("08", 10)); // ✅ Correct output: 8

Why is this better?
Ensures correct number interpretation.
✔ Works across all browsers consistently.

6️⃣ Ignoring Function Scope When Using this

Problem: JavaScript’s this behaves differently in arrow functions and regular functions.

Bad Code (this Losing Context)

class User {
    constructor(name) {
        this.name = name;
    }

    printName() {
        setTimeout(function () {
            console.log(this.name); // ❌ Undefined
        }, 1000);
    }
}
new User("John").printName();

🔴 Issue: this inside setTimeout refers to the global object, not User.

Good Code (Using Arrow Functions)

class User {
    constructor(name) {
        this.name = name;
    }

    printName() {
        setTimeout(() => {
            console.log(this.name); // ✅ Correctly prints "John"
        }, 1000);
    }
}

Why is this better?
Arrow functions inherit this from their surrounding scope.

7️⃣ Overwriting Built-in Prototypes

Problem: Modifying built-in prototypes (Array, Object, etc.) can break third-party libraries.

Bad Code (Modifying Array Prototype)

Array.prototype.removeFirst = function () {
    this.shift();
};

🔴 Issue: Extending built-in prototypes can cause unexpected side effects.

Good Code (Using Utility Functions)

function removeFirst(arr) {
    return arr.slice(1);
}

Why is this better?
✔ Keeps built-in objects intact.
Safer for third-party libraries.

8️⃣ Ignoring Floating Point Precision Issues

Problem: JavaScript cannot precisely represent some decimal numbers.

Bad Code (Relying on Floating-Point Precision)

console.log(0.1 + 0.2 === 0.3); // ❌ false

🔴 Issue: Due to floating-point math, 0.1 + 0.2 !== 0.3 exactly.

Good Code (Using .toFixed() or Math Libraries)

console.log((0.1 + 0.2).toFixed(2) === "0.30"); // ✅ true

Why is this better?
✔ Ensures consistent rounding.
✔ Avoids unexpected calculations.

9️⃣ Not Handling Errors in Promises

Problem: Unhandled errors in asynchronous code can crash applications.

Bad Code (No .catch())

fetch("https://api.example.com/data")
    .then(response => response.json());

🔴 Issue: If the request fails, there’s no error handling.

Good Code (Adding .catch())

fetch("https://api.example.com/data")
    .then(response => response.json())
    .catch(error => console.error("Error fetching data:", error));

Why is this better?
Prevents unhandled rejections.

🔟 Blocking the Event Loop with Heavy Computation

Problem: JavaScript runs on a single thread, meaning heavy operations freeze the UI.

Bad Code (Blocking the Event Loop)

for (let i = 0; i < 1e9; i++) { } // ❌ Freezes the browser

Good Code (Using setTimeout())

function processLargeTask() {
    setTimeout(() => {
        for (let i = 0; i < 1e6; i++) { } // ✅ Runs without freezing
    }, 0);
}

Why is this better?
✔ Prevents UI from becoming unresponsive.

📌 Conclusion

By avoiding these 10 JavaScript mistakes, you can write cleaner, faster, and more reliable code. 🚀

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare