10 Common JavaScript Errors and How to Avoid Them

JavaScript, the backbone of modern web development, empowers developers to create dynamic and interactive websites.

However, mastering this language comes with challenges. Even experienced developers often encounter stumbling blocks in the form of common JavaScript errors. But they’re avoidable. Let’s begin diving into some of the common errors you may encounter.

1. Undefined is Not a Function

Imagine you’re trying to call a function that hasn’t been defined yet. This often happens when the function is declared after the point where it’s called in the code. Take a look at the example below.

// Bad practice
calculateTotal(); // Error: calculateTotal is not a function
// Function declaration appears later in the code
const calculateTotal = () => {
  // code here
};

Calling calculateTotal() before the function is declared will result in an error because at that point in the code, calculateTotal is undefined. The JavaScript engine hasn’t got to it yet.

To avoid this error, always ensure that you call functions after they have been properly defined, like so:

// Function declaration appears before the function call
const calculateTotal = () => {
  // code here
};

calculateTotal(); // No error, function is defined before the call

This relates to variable scope, i.e. where variables are defined within your code. There’s a brilliant book (free to read online), here: You Don’t Know JS Yet: Scope & Closures, if you’d like to explore the topic a bit more.

2. Typos and Case Sensitivity

JavaScript is case-sensitive, meaning if we had two variables, name and Name, they would be totally different in memory.

Typos can lead to errors that are hard to spot. Pay close attention to your variable names and function calls, ensuring consistency throughout your code.

// Bad practice
Console.log("Hello, World!");

// Good practice
console.log("Hello, World!");

Not a lot needs to be said here, just beware that JavaScript is case-sensitive.

3. Parentheses and Brackets Mismatch

This is another cause of frustration. Mismatched parentheses and brackets often cause errors (and headaches!). Always double-check opening and closing brackets, ensuring they match up correctly.

// Bad practice
if (condition {
    // code here
}

// Good practice
if (condition) {
    // code here
}

4. NaN (Not a Number)

When dealing with mathematical operations, be cautious. JavaScript returns ‘NaN’ when an operation fails. To avoid this, validate your inputs before performing calculations.

// Bad practice
const result = parseInt("abc123");

// Good practice
const input = "abc123";
const result = parseInt(input);
if (!isNaN(result)) {
  console.log("Hello");
}

5. Semicolon Insertion

JavaScript automatically inserts semicolons, but it’s best not to rely on this behavior. Explicitly adding semicolons helps prevent unexpected errors, especially in complex code.

// Bad practice
let a = 10
let b = 20

// Good practice
let a = 10;
let b = 20;

Now, lots of people ignore semicolons altoghether, but we absolutely dislike that! However, if you know the rules around semicolons, you can indeed skip them (don’t do it… (kidding, of course)).

6. Asynchronous Callbacks

Asynchronous operations are quite fundamental in JavaScript, allowing programs to execute tasks without waiting, which ensures a smooth user experience.

However, handling asynchronous code, especially with callbacks, can be tricky and often leads to errors.

Let’s delve deeper into this common stumbling block and understand how to handle asynchronous callbacks effectively.

Consider a scenario where you want to fetch data from an API and perform actions based on that data. Due to the nature of APIs, this operation is asynchronous, meaning it takes time to complete, and the program doesn’t halt and wait for it. Instead, JavaScript continues executing the next lines of code.

// Bad practice
const fetchData = () => {
  let data;
  fetch("https://api.example.com/data")
    .then((response) => response.json())
    .then((result) => {
      data = result;
    });
  return data; // Incorrect: This returns undefined as fetch hasn't completed yet
}

// Good practice
const fetchData = callback => {
  fetch("https://api.example.com/data")
    .then((response) => response.json())
    .then((result) => {
      callback(result); // Correct: Pass the data to the callback function
    });
}

fetchData(data => {
  console.log(data); // Process data inside the callback function
});

In the bad practice example, the fetchData function attempts to return data fetched from an API. However, due to the asynchronous nature of fetch, the function returns before the data is available, leading to undefined.

The good practice example demonstrates the use of callbacks. Instead of trying to return the asynchronous result directly, the function accepts a callback parameter. Once the data is fetched, it’s passed to the callback function for further processing. This ensures that operations depending on the fetched data occur only after the asynchronous task is completed.

Further, modern JavaScript introduces powerful features to handle asynchronous code elegantly, such as async/await. Here’s how you could rewrite the fetchData function using async/await:

// Using async/await
async function fetchData() {
  try {
    let response = await fetch("https://api.example.com/data");
    let data = await response.json();
    return data;
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}

fetchData().then((data) => {
  console.log(data); // Process data inside the promise resolution
});

async/await simplifies the asynchronous code, making it appear synchronous while preserving its non-blocking nature.

The fetchData function fetches data, waits for the response, processes it, and then returns the data when the operation is successful.

By understanding asynchronous callbacks and leveraging modern JavaScript features, you can handle asynchronous operations effectively, preventing common errors and ensuring your JavaScript code operates seamlessly in real-world scenarios.

7. Uncaught TypeErrors

TypeErrors often occur due to mismatched data types. To avoid them, validate your variables' types before performing operations on them.

// Bad practice
const number = "123";
const sum = number + 5;

console.log(sum); // '1235'

// Good practice
const number = "123";
const parsedNumber = parseInt(number);
if (!isNaN(parsedNumber)) {
  let sum = parsedNumber + 5;
}

8. Infinite Loops

Infinite loops can crash your application. Always ensure there’s a condition that allows the loop to exit, preventing it from running endlessly.

// Bad practice
while (true) {
  // code here
}

// Good practice
let condition = true;
while (condition) {
  // code here
}

9. Overwriting Variables

Accidentally overwriting variables can lead to unexpected behavior. Be mindful of variable scopes and avoid reusing variable names unintentionally.

// Bad practice
const calculateTotal = (price) => {
  let total = 0;
  for (let i = 0; i < price.length; i++) {
    let total = total + price[i];
  }
  return total;
};

// Good practice
const calculateTotal = (price) => {
  let total = 0;
  for (let i = 0; i < price.length; i++) {
    total = total + price[i];
  }
  return total;
};

10. Ignoring Browser Compatibility

Different browsers interpret JavaScript code differently. Always consider cross-browser compatibility and test your code on multiple browsers to avoid unexpected errors on specific platforms.

There’s a useful website, Can I Use to check for browser compatibility. Bookmark it and refer to it often!

Conclusion

By understanding and sidestepping these common JavaScript errors, you’re well on your way to writing robust and error-free code. Continuous learning and attention to detail are your allies in the ever-evolving landscape of web development.

Stay vigilant, keep practicing, and soon, these errors will be mere speed bumps on your coding journey. Happy coding!

JavaScript Today Book

Want to learn more vanilla JavaScript concepts? Check out our book: The Impatient Programmer’s Guide to JavaScript. We worked really hard on this, and would highly appreciate your support! (totally not necessary).

We 💓 our readers.

If you truly cannot afford the book, send us an email: contact@javascripttoday.com. We’ll send you a free copy.

comments powered by Disqus

Related Posts

Creating a Real Time Chat Application with React, Node, and TailwindCSS

In this tutorial, we will show you how to build a real-time chat application using React and Vite,as well as a simple Node backend.

Read more

The Importance of Staying Active as a Software Developer

In today’s fast-paced digital world, developers often find themselves glued to their screens for extended periods. While this dedication is commendable, it comes with its own set of challenges.

Read more

JavaScript DOM Mastery: Top Interview Questions Explained

Mastering the Document Object Model (DOM) is crucial for any JavaScript developer. While many developers rely heavily on front-end frameworks, the underlying DOM concepts are still important.

Read more