Debugging and Best Practices
What Is Debugging?
Debugging is the process of finding and fixing errors (bugs) in your code. Every developer—beginner or expert—spends time debugging. The key is knowing how to debug efficiently.
Types of Errors
1. Syntax Errors
Code that violates JavaScript’s grammar rules. These prevent code from running at all.
// ❌ Missing closing parenthesis
console.log("Hello";
// ❌ Missing closing bracket
let arr = [1, 2, 3;
// ❌ Misspelled keyword
funciton greet() {
console.log("Hi");
}
// ❌ Missing quotes
let name = Alice;
How to fix: Check the error message—it usually points to the line with the problem.
2. Runtime Errors
Code that’s syntactically correct but fails during execution.
// ❌ Calling undefined function
greet(); // ReferenceError: greet is not defined
// ❌ Accessing property of undefined
let user;
console.log(user.name); // TypeError: Cannot read property 'name' of undefined
// ❌ Dividing by zero (returns Infinity, not an error in JS)
let result = 10 / 0;
console.log(result); // Infinity
3. Logical Errors
Code runs without errors, but produces incorrect results.
// ❌ Off-by-one error
for (let i = 0; i <= arr.length; i++) { // Should be < not <=
console.log(arr[i]);
}
// ❌ Wrong operator
if (age = 18) { // Should be === not =
console.log("You are 18");
}
// ❌ Wrong calculation
let discount = price * 0.1;
let finalPrice = price + discount; // Should be - not +
Console Methods for Debugging
console.log() — Basic Output
let name = "Alice";
let age = 25;
console.log("Name:", name);
console.log("Age:", age);
// Multiple values
console.log("User:", name, "Age:", age);
// With template literals
console.log(`User: ${name}, Age: ${age}`);
console.error() — Error Messages
function divide(a, b) {
if (b === 0) {
console.error("Cannot divide by zero!");
return;
}
return a / b;
}
console.warn() — Warnings
function deprecatedFunction() {
console.warn("This function is deprecated. Use newFunction() instead.");
}
console.table() — Display Arrays/Objects
let users = [
{name: "Alice", age: 25},
{name: "Bob", age: 30},
{name: "Carol", age: 28}
];
console.table(users);
// Displays a nicely formatted table
console.assert() — Conditional Logging
let age = 15;
console.assert(age >= 18, "User must be 18 or older");
// Only logs if condition is false
console.time() and console.timeEnd() — Performance
console.time("loop");
for (let i = 0; i < 1000000; i++) {
// Some operation
}
console.timeEnd("loop");
// Output: loop: 5.234ms
console.clear() — Clear Console
console.clear(); // Clears all console output
Browser DevTools
Modern browsers include powerful debugging tools. Press F12 or Cmd+Option+I (Mac) / Ctrl+Shift+I (Windows) to open DevTools.
Console Tab
- View console.log() output
- See errors and warnings
- Run JavaScript commands interactively
- Access DOM elements
Try in console:
document.querySelector('body').style.backgroundColor = 'lightblue';
Sources Tab — Debugging Code
Set breakpoints:
- Open Sources tab
- Find your JavaScript file
- Click line number to set breakpoint
- Reload page—execution pauses at breakpoint
Controls:
- Resume (
F8): Continue execution - Step Over (
F10): Execute current line, don’t enter functions - Step Into (
F11): Enter function calls - Step Out (
Shift+F11): Exit current function
Watch variables:
- Right panel shows current variable values
- Add watches to monitor specific variables
Elements Tab
- Inspect HTML structure
- View and modify CSS
- See applied styles
- Test style changes live
Network Tab
- Monitor HTTP requests
- Check API responses
- Debug loading issues
- View request/response headers
Debugging Techniques
1. Read Error Messages Carefully
// Error: Uncaught ReferenceError: greet is not defined
// at script.js:10
// What it tells you:
// - Type: ReferenceError (variable/function doesn't exist)
// - Problem: greet is not defined
// - Location: script.js, line 10
2. Use console.log() Strategically
function calculateTotal(items) {
console.log("calculateTotal called with:", items);
let total = 0;
for (let item of items) {
console.log("Processing item:", item);
total += item.price * item.quantity;
}
console.log("Final total:", total);
return total;
}
3. Isolate the Problem
Comment out code to find where the error occurs:
// Code works fine
console.log("Part 1 works");
// Problematic code?
// functionThatMightFail();
// Does this run?
console.log("Did Part 2 run?");
4. Check Data Types
function add(a, b) {
console.log("Type of a:", typeof a);
console.log("Type of b:", typeof b);
return a + b;
}
add("5", 3); // Output: "53" (string concatenation, not addition!)
5. Validate Assumptions
let element = document.getElementById("myElement");
console.log("Element found?", element !== null);
if (element) {
element.textContent = "Updated!";
} else {
console.error("Element not found! Check ID spelling.");
}
6. Use debugger Statement
Forces JavaScript to pause execution (if DevTools are open).
function complexFunction(data) {
debugger; // Execution pauses here
// Inspect variables in DevTools
let result = data.map(item => item * 2);
return result;
}
Common Errors and Solutions
Error 1: ReferenceError
Problem: Variable or function doesn’t exist.
// ❌ Error
console.log(userName); // ReferenceError: userName is not defined
// ✅ Solution: Declare the variable
let userName = "Alice";
console.log(userName);
Error 2: TypeError
Problem: Trying to use wrong type or access property of null/undefined.
// ❌ Error
let user = null;
console.log(user.name); // TypeError: Cannot read property 'name' of null
// ✅ Solution: Check before accessing
if (user) {
console.log(user.name);
} else {
console.log("User is null");
}
// ✅ Optional chaining (modern)
console.log(user?.name); // undefined (no error)
Error 3: Undefined Is Not a Function
Problem: Trying to call something that isn’t a function.
// ❌ Error
let calculate = 5;
calculate(); // TypeError: calculate is not a function
// ✅ Solution: Ensure it's a function
let calculate = function() {
return 5;
};
calculate(); // Works
Error 4: Cannot Read Property of Undefined
Problem: Accessing property before object is set.
// ❌ Error
let user;
console.log(user.name); // TypeError
// ✅ Solution: Initialize properly
let user = {name: "Alice"};
console.log(user.name); // Works
Error 5: Unexpected Token
Problem: Syntax error (missing bracket, comma, quote).
// ❌ Error
let obj = {
name: "Alice"
age: 25 // Missing comma!
};
// ✅ Solution
let obj = {
name: "Alice",
age: 25
};
JavaScript Best Practices
1. Use Strict Mode
Catches common mistakes and prevents bad practices.
"use strict";
// This would fail in strict mode
undeclaredVariable = 10; // ReferenceError
2. Variable Naming Conventions
// ✅ Good: Descriptive, camelCase
let firstName = "Alice";
let totalPrice = 99.99;
let isLoggedIn = true;
// ❌ Bad: Unclear, abbreviations
let fn = "Alice";
let tp = 99.99;
let li = true;
// Constants: UPPERCASE_WITH_UNDERSCORES
const MAX_USERS = 100;
const API_BASE_URL = "https://api.example.com";
3. Use const and let, Never var
// ✅ Good
const PI = 3.14159;
let counter = 0;
// ❌ Bad (outdated)
var x = 10;
4. Always Use Semicolons
// ✅ Good
let name = "Alice";
console.log(name);
// ❌ Can cause issues (ASI is unpredictable)
let name = "Alice"
console.log(name)
5. Use === Instead of ==
// ❌ Loose equality (type coercion)
console.log(5 == "5"); // true (unexpected!)
console.log(0 == false); // true (unexpected!)
// ✅ Strict equality
console.log(5 === "5"); // false (correct!)
console.log(0 === false); // false (correct!)
6. Keep Functions Small and Focused
// ❌ Bad: Function does too much
function processUserData(user) {
// Validate user
// Update database
// Send email
// Update UI
// Log activity
}
// ✅ Good: Single responsibility
function validateUser(user) { ... }
function updateDatabase(user) { ... }
function sendEmail(user) { ... }
function updateUI(user) { ... }
function logActivity(action) { ... }
7. Use Meaningful Names
// ❌ Bad
function f(x, y) {
return x * y * 0.08;
}
// ✅ Good
function calculateSalesTax(price, quantity) {
const TAX_RATE = 0.08;
return price * quantity * TAX_RATE;
}
8. Add Comments for Complex Logic
// Calculate compound interest
// Formula: A = P(1 + r)^t
function calculateCompoundInterest(principal, rate, time) {
return principal * Math.pow(1 + rate, time);
}
// ❌ Don't comment obvious code
let x = 5; // Set x to 5 (redundant!)
// ✅ Explain WHY, not what
let retryDelay = 5000; // Wait 5 seconds to avoid rate limiting
9. Handle Errors Gracefully
// ✅ Check for potential errors
function divide(a, b) {
if (b === 0) {
console.error("Cannot divide by zero");
return null;
}
return a / b;
}
// ✅ Try-catch for external operations
async function fetchData(url) {
try {
const response = await fetch(url);
const data = await response.json();
return data;
} catch (error) {
console.error("Failed to fetch data:", error);
return null;
}
}
10. Don’t Repeat Yourself (DRY)
// ❌ Bad: Repeated code
let user1Total = user1.items * user1.price * 1.08;
let user2Total = user2.items * user2.price * 1.08;
let user3Total = user3.items * user3.price * 1.08;
// ✅ Good: Reusable function
function calculateTotal(user) {
const TAX_RATE = 1.08;
return user.items * user.price * TAX_RATE;
}
let user1Total = calculateTotal(user1);
let user2Total = calculateTotal(user2);
let user3Total = calculateTotal(user3);
11. Avoid Global Variables
// ❌ Bad: Pollutes global scope
var globalCounter = 0;
function increment() {
globalCounter++;
}
// ✅ Good: Use modules or closures
function createCounter() {
let count = 0;
return {
increment() {
count++;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
12. Use Template Literals
// ❌ Bad: String concatenation
let message = "Hello, " + name + "! You have " + count + " messages.";
// ✅ Good: Template literals
let message = `Hello, ${name}! You have ${count} messages.`;
Performance Best Practices
1. Cache DOM Selections
// ❌ Bad: Queries DOM repeatedly
for (let i = 0; i < 100; i++) {
document.getElementById("output").textContent = i;
}
// ✅ Good: Cache the element
let output = document.getElementById("output");
for (let i = 0; i < 100; i++) {
output.textContent = i;
}
2. Minimize DOM Manipulation
// ❌ Bad: Many small DOM changes
let list = document.getElementById("list");
for (let i = 0; i < 100; i++) {
let li = document.createElement("li");
li.textContent = `Item ${i}`;
list.appendChild(li); // Reflows DOM 100 times!
}
// ✅ Good: Build string, insert once
let html = "";
for (let i = 0; i < 100; i++) {
html += `<li>Item ${i}</li>`;
}
list.innerHTML = html; // Single DOM update
3. Use Event Delegation
// ❌ Bad: Listener on each item
items.forEach(item => {
item.addEventListener("click", handleClick);
});
// ✅ Good: Single listener on parent
parent.addEventListener("click", (e) => {
if (e.target.classList.contains("item")) {
handleClick(e);
}
});
Code Organization
1. Group Related Code
// ✅ Good: Organized sections
// ========== Configuration ==========
const API_URL = "https://api.example.com";
const TIMEOUT = 5000;
// ========== Helper Functions ==========
function formatDate(date) { ... }
function validateEmail(email) { ... }
// ========== Main Logic ==========
function init() { ... }
function loadData() { ... }
2. Use Modules
// utils.js
export function formatCurrency(amount) {
return `$${amount.toFixed(2)}`;
}
// main.js
import { formatCurrency } from './utils.js';
console.log(formatCurrency(19.99));
Next Steps in Your JavaScript Journey
Congratulations on completing JavaScript Fundamentals! Here’s what to learn next:
Immediate Next Steps
- Build more projects: Practice is key!
- Learn ES6+ features: Destructuring, spread operator, async/await
- Master Array methods: map, filter, reduce, etc.
- Study the DOM deeply: Events, performance, accessibility
Intermediate Level
- Asynchronous JavaScript: Promises, async/await, fetch API
- JavaScript Frameworks: React, Vue, or Angular
- Node.js: Backend JavaScript
- Module bundlers: Webpack, Vite
- Version control: Git and GitHub
Advanced Topics
- Design patterns: Module, Observer, Factory, etc.
- Testing: Jest, Mocha, unit tests
- TypeScript: Typed JavaScript
- Performance optimization: Debouncing, throttling, memoization
- Web APIs: localStorage, geolocation, notifications
Resources for Continued Learning
Documentation
- MDN Web Docs: Official reference
- JavaScript.info: Modern tutorial
- Eloquent JavaScript: Free book
Practice Platforms
- freeCodeCamp: Interactive lessons
- Codecademy: Structured courses
- LeetCode: Algorithm practice
- CodeWars: Coding challenges
Community
- Stack Overflow: Ask questions
- Reddit r/learnjavascript: Community support
- Discord/Slack communities: Real-time help
- Local meetups: Network with developers
Key Takeaways
✅ Debugging is a skill—practice makes perfect
✅ Use browser DevTools for efficient debugging
✅ Read error messages carefully—they guide you to the problem
✅ console.log() is your friend—use it liberally
✅ Always use const and let, never var
✅ Use === instead of == for comparisons
✅ Write small, focused functions with single responsibilities
✅ Add comments for complex logic, not obvious code
✅ Handle errors gracefully with validation and try-catch
✅ Optimize performance by caching DOM queries and minimizing manipulation
✅ Keep learning—JavaScript evolves constantly!
Final Words
You’ve completed JavaScript Fundamentals! You now have a solid foundation in:
- Variables, data types, and operators
- Control flow and loops
- Functions and scope
- Arrays and objects
- DOM manipulation
- Event handling
- Debugging techniques
- Best practices
Most importantly: You’ve built a complete project and know how to apply these concepts in real applications.
Keep building, keep learning, and keep coding. The JavaScript journey has just begun!