DEV Community

Cover image for Common JavaScript Bugs (And How to Avoid Them)
Muhammad Zaheer
Muhammad Zaheer

Posted on

Common JavaScript Bugs (And How to Avoid Them)

JavaScript is everywhere from simple UI interactions to full-scale applications.

If you’ve worked with JavaScript long enough, you’ve probably seen code that looks correct but behaves in unexpected ways.

In this article, we’ll explore some common JavaScript bugs, why they happen, and how to avoid them in real projects.

1. Undefined vs Null Confusion

This bug happens when a variable is accessed before it has been properly initialized.It often leads to runtime errors that are confusing for beginners.

Problematic Code

let user;
console.log(user.name);
Enter fullscreen mode Exit fullscreen mode

Correct Approach

let user = null;

if (user !== null) {
  console.log(user.name);
}
Enter fullscreen mode Exit fullscreen mode

Why This Happens
undefined means a variable exists but has no value. Accessing properties on it causes an error.

  • Best Practice

Always initialize variables and check them before use.

  • Using == Instead of === Using loose equality can cause unexpected results due to type coercion.

Problematic Code

0 == false; // true
Enter fullscreen mode Exit fullscreen mode

Correct Approach

0 === false; // false
Enter fullscreen mode Exit fullscreen mode

Why This Happens

The == operator converts values before comparison, which can lead to logical bugs.

  • Best Practice

Always use === for comparisons.

Scope Issues with var

Variables declared with var are not block-scoped, which can cause unexpected behavior.

if (true) {
  var count = 10;
}
console.log(count);
Enter fullscreen mode Exit fullscreen mode
if (true) {
  let count = 10;
}
Enter fullscreen mode Exit fullscreen mode

let and const respect block scope, making code safer and easier to debug. Modern JavaScript should avoid var.

Forgetting return in Functions

Functions return undefined by default if no return statement is provided.

function add(a, b) {
  a + b;
}
Enter fullscreen mode Exit fullscreen mode
function add(a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

Always ensure your function explicitly returns the expected value.

Asynchronous Code Misunderstanding

JavaScript does not wait for asynchronous operations unless instructed.

let data;

fetch("/api/data").then(res => {
  data = res;
});

console.log(data);
Enter fullscreen mode Exit fullscreen mode
async function getData() {
  const res = await fetch("/api/data");
  console.log(res);
}

getData();
Enter fullscreen mode Exit fullscreen mode

Using async and await makes asynchronous code easier to understand and prevents timing-related bugs.

Mutating Objects or Arrays by Mistake

Objects and arrays are passed by reference, not copied.

const users = [];
const newUsers = users;
newUsers.push("Ali");
Enter fullscreen mode Exit fullscreen mode
const users = [];
const newUsers = [...users, "Ali"];
Enter fullscreen mode Exit fullscreen mode

Creating copies prevents unintended side effects in applications.

Accessing Undefined Object Properties

Accessing deep object properties without checks can crash your application.

console.log(user.profile.age);
Enter fullscreen mode Exit fullscreen mode
console.log(user?.profile?.age);

Enter fullscreen mode Exit fullscreen mode

Optional chaining safely handles missing data and avoids runtime errors.

Misusing the this Keyword

The value of this depends on how a function is called.

setTimeout(function () {
  console.log(this.name);
}, 1000);
Enter fullscreen mode Exit fullscreen mode
setTimeout(() => {
  console.log(this.name);
}, 1000);
Enter fullscreen mode Exit fullscreen mode

Arrow functions do not bind their own this, making them safer inside callbacks.

Ignoring Error Handling

Unhandled errors can stop your entire application.
JSON.parse(data);

try {
  JSON.parse(data);
} catch (error) {
  console.error("Invalid JSON");
}
Enter fullscreen mode Exit fullscreen mode

Proper error handling makes applications more stable and user-friendly.

Conclusion

Most JavaScript bugs are not complex problems. They come from small assumptions and misunderstandings. By understanding scope, equality, asynchronous behavior, and data handling, developers can write cleaner, safer, and more predictable JavaScript code.

About the Author

Muhammad Zaheer is a JavaScript and Web Developer with a strong focus on writing clean, maintainable, and practical code for real-world applications. He enjoys breaking down complex programming concepts into simple explanations that developers can easily understand and apply in their daily work.

He actively shares knowledge, learns from the developer community, and works on modern web solutions with a focus on performance, scalability, and user experience. You can connect with him on LinkedIn
to follow his work and professional journey.

To learn more about his background, skills, and experience, visit his official team profile.

Top comments (0)