Skip to content

Common JavaScript Mistakes

This lesson explains Common JavaScript Mistakes in JavaScript with beginner-friendly examples, practical use cases, and clear best practices.

JavaScript Common Mistakes Overview

JavaScript common mistakes are coding errors, bad habits, and confusing language behaviors that can create bugs in real applications. These mistakes often happen with variables, scope, hoisting, functions, arrays, objects, DOM manipulation, events, promises, async/await, Fetch API, storage, security, and performance.

Understanding common JavaScript pitfalls helps developers write safer, cleaner, and more maintainable code. This lesson covers 50 frequent JavaScript mistakes with examples and recommended fixes for beginners, frontend developers, full-stack developers, and interview preparation.

JavaScript Common Mistakes Example

// Mistake: using var, loose equality, and unsafe DOM update

var age = "18";

if (age == 18) {
  document.querySelector("#message").innerHTML = "Access allowed";
}

// Better: use const, strict equality, and textContent

const userAge = 18;

if (userAge === 18) {
  document.querySelector("#message").textContent = "Access allowed";
}

This example shows common mistakes such as using var, relying on loose equality, and using innerHTML when plain text is safer.

50 JavaScript Common Mistakes and Pitfalls

The following table lists common JavaScript mistakes, why they are a problem, and safer examples to use in real projects.

# Common Mistake Why It Is a Problem Better Syntax
1Using var in modern code.Creates hoisting and function-scope confusion.const name = "John";
2Using == instead of ===.Can cause unexpected type coercion.if (age === 18) { allowAccess(); }
3Reassigning values unnecessarily.Makes code harder to reason about.const total = price + tax;
4Using unclear variable names.Reduces readability and maintainability.const totalPrice = price + tax;
5Creating unnecessary global variables.Can cause naming conflicts and side effects.function getTotal() { const total = 100; return total; }
6Accessing variables before declaration.Causes undefined or ReferenceError.const count = 1; console.log(count);
7Expecting let and const to work before declaration.They are in the temporal dead zone.let score = 10;
8Calling function expressions before assignment.Function expression is not initialized before execution.const greet = function() { return "Hi"; };
9Using arrow functions as object methods with this.Arrow functions do not have their own this.const user = { name: "John", getName() { return this.name; } };
10Losing this when passing methods as callbacks.The method context may be lost.const bound = user.getName.bind(user);
11Writing large functions.Hard to test, debug, and reuse.function validateEmail(email) { return email.includes("@"); }
12Mixing many responsibilities in one function.Creates tightly coupled code.function formatPrice(price) { return "$" + price; }
13Forgetting to return from map().Produces an array of undefined.const names = users.map(user => user.name);
14Using map() for side effects.map() should transform values.users.forEach(user => console.log(user.name));
15Using filter() when only one item is needed.Returns an array instead of one item.const user = users.find(user => user.id === 1);
16Forgetting initial value in reduce().Can fail with empty arrays.const total = prices.reduce((sum, price) => sum + price, 0);
17Mutating arrays unexpectedly.Can cause hidden bugs in state updates.const updated = [...items, newItem];
18Mutating objects unexpectedly.Can break predictable state management.const updatedUser = { ...user, active: true };
19Expecting spread syntax to deep clone objects.Spread only creates a shallow copy.const copy = structuredClone(user);
20Accessing nested properties without checks.Can throw errors when data is missing.const city = user.address?.city;
21Using || when 0 is valid.Falsy values may be replaced incorrectly.const limit = settings.limit ?? 10;
22Comparing objects by reference incorrectly.Different object references are not equal.const sameId = userA.id === userB.id;
23Using for...in for arrays.It loops keys, not array values.for (const item of items) { console.log(item); }
24Forgetting array indexes start at 0.Can access the wrong item.const firstItem = items[0];
25Sorting numbers without a compare function.Default sort compares values as strings.numbers.sort((a, b) => a - b);
26Using innerHTML with user input.Can create security risks.message.textContent = userInput;
27Selecting DOM elements before they exist.Returns null and causes errors.document.addEventListener("DOMContentLoaded", init);
28Not checking selected elements.Calling methods on null throws errors.if (button) { button.addEventListener("click", handleClick); }
29Adding duplicate event listeners.Runs the same logic multiple times.button.addEventListener("click", handleClick);
30Not using event delegation for dynamic lists.New elements may not have listeners.list.addEventListener("click", function(event) { console.log(event.target); });
31Forgetting event.preventDefault() on custom form submit.The page may reload unexpectedly.form.addEventListener("submit", function(event) { event.preventDefault(); });
32Trusting frontend validation only.Frontend checks can be bypassed.// Validate again on the server
33Ignoring promise rejections.Can cause hidden async failures.fetchUsers().catch(handleError);
34Forgetting await.You may get a Promise instead of actual data.const users = await fetchUsers();
35Running independent async tasks one by one.Slower than running in parallel.const data = await Promise.all([getUsers(), getOrders()]);
36Not checking response.ok with Fetch API.Fetch does not reject for HTTP errors.if (!response.ok) { throw new Error("Request failed"); }
37Forgetting response.json() returns a Promise.Data may not be available yet.const data = await response.json();
38Sending objects without JSON.stringify().Request body may be incorrect.body: JSON.stringify(user)
39Parsing invalid JSON without handling errors.Can crash the application.try { JSON.parse(text); } catch (error) { showError(); }
40Using localStorage for sensitive data.Browser storage can be accessed by scripts.// Store sensitive data on the server
41Forgetting browser storage stores strings only.Objects become incorrect string values.localStorage.setItem("user", JSON.stringify(user));
42Leaving intervals running.Can cause memory leaks and repeated work.clearInterval(intervalId);
43Using setInterval() for slow API polling.Requests may overlap.setTimeout(pollAgain, 5000);
44Assuming setTimeout(..., 0) runs immediately.It runs after the current call stack.setTimeout(callback, 0);
45Blocking the UI with heavy synchronous code.Makes the page freeze.setTimeout(function() { processChunk(); }, 0);
46Using timers for smooth animations.Animation may be janky.requestAnimationFrame(animate);
47Not debouncing frequent events.Can cause performance issues.clearTimeout(timer); timer = setTimeout(search, 300);
48Throwing plain strings.Loses useful error details.throw new Error("Invalid input");
49Catching errors but doing nothing.Hides bugs and makes debugging hard.catch (error) { console.log(error.message); }
50Over-engineering simple code.Makes code harder to maintain.const total = price + tax;

Key Takeaways

  • Common JavaScript mistakes often come from scope, hoisting, coercion, async code, DOM updates, and storage.
  • Use const, let, strict equality, descriptive names, and small functions.
  • Handle errors in promises, async/await, Fetch API, and JSON parsing.
  • Use safer DOM APIs such as textContent when inserting plain text.
  • Validate input on both frontend and backend.
  • Avoid storing sensitive information in browser storage.

Pro Tip

Most JavaScript bugs come from unclear data flow, unexpected type coercion, missing error handling, unsafe DOM updates, and misunderstood async behavior. Write predictable code and handle edge cases early.