Course: JavaScript Beginner
Lesson 19: Basic Debugging with Console and DevTools
Level
Beginner
Estimated Reading Time
10–15 minutes
Goal
By the end of this lesson, the learner will be able to:
- Use
console.log,console.warn, andconsole.errorto inspect values at runtime - Read and understand common JavaScript error messages in the browser console
- Use
typeofand conditional logging to diagnose unexpected behavior
Frontend Development Context
Debugging is not a sign that something went wrong with your learning — it is a normal, daily part of professional software development. Even experienced developers spend significant time figuring out why code does not behave as expected. The difference between a beginner and a professional is often not the number of bugs they write, but how quickly and systematically they find and fix them.
The browser's DevTools console is your primary window into what your JavaScript is doing. Learning to use it effectively — knowing which log methods to use, how to read error messages, and how to narrow down where a problem lives — is one of the highest-return skills you can develop in your early JavaScript learning.
Explanation
console.log(value) prints a value to the browser console. You can pass multiple values separated by commas: console.log("Name:", name, "Age:", age). Objects and arrays are displayed interactively in the console, so you can expand them to see their properties. This is the most-used debugging tool in JavaScript.
console.warn(message) prints a yellow warning message. console.error(message) prints a red error message. These are useful for intentionally marking unexpected states or conditions in your code — they do not stop execution, but they stand out visually in the console.
console.table(array) displays an array of objects as a formatted table in the console — very helpful when debugging lists of data. console.group(label) and console.groupEnd() collapse related log messages into an expandable group.
Reading error messages: When JavaScript throws an error, the console shows the error type, the message, and a stack trace showing which file and line number caused the error. The most common error types beginners encounter are:
TypeError— you tried to call something that is not a function, or access a property onnullorundefinedReferenceError— you used a variable name that has not been declaredSyntaxError— your code has invalid syntax (missing bracket, typo in a keyword, etc.)
typeof value returns a string describing the type of a value. It is useful for diagnosing type mismatches when a variable holds an unexpected type.
Breakpoints in DevTools let you pause execution at a specific line, inspect all variables in scope, and step through code line by line. You can set them by clicking a line number in the Sources tab, or by adding debugger; to your code.
Code Example
This example demonstrates several debugging techniques while processing a list of user data:
const users = [
{ name: "Alice", age: 28, role: "admin" },
{ name: "Bob", age: null, role: "viewer" },
{ name: "Charlie", age: "thirty", role: "editor" },
];
console.table(users); // see all users in a clean table
users.forEach((user, index) => {
console.group(`User ${index + 1}: ${user.name}`);
console.log("Role:", user.role);
console.log("Age type:", typeof user.age); // spot the string and null
if (typeof user.age !== "number") {
console.warn(`Age for ${user.name} is not a number:`, user.age);
}
if (user.age === null) {
console.error(`Missing age for ${user.name}`);
}
console.groupEnd();
});
Code Explanation
console.table(users) renders the array of user objects as a table with columns for each property. This is far easier to scan than multiple console.log calls and immediately reveals that Bob's age is null and Charlie's is a string.
The console.group call creates a collapsible section in the console for each user. Grouping related logs together is helpful when you are logging information about multiple items — it keeps the console readable instead of producing a wall of interleaved messages.
typeof user.age !== "number" catches both the null and the string "thirty" cases, since typeof null is "object" and typeof "thirty" is "string" — neither is "number". The console.warn highlights the problem without stopping execution.
The separate null check uses console.error because missing age data is more severe — it might cause a calculation to fail downstream. Using different severity levels (log, warn, error) makes it easier to prioritize which issues to fix first when scanning the console output.
Pattern Highlights
✅ Positive Pattern: Log the variable name alongside its value:
console.log("user:", user)rather than justconsole.log(user). This makes multi-log output readable when you have many logs at once.
⚠️ Neutral Note: Remove debugging
console.logstatements from code before deploying to production. Left-over logs can expose sensitive data and clutter the console for users who happen to open DevTools.
❌ Negative Pattern: Adding
console.logonly at the very end to check the final result — if the result is wrong, you still do not know where it went wrong. Log intermediate values at each step to narrow down the source of the problem.
Common Mistakes
Mistake 1: Logging an object and trusting the initial display
When you log an object with console.log(obj), the browser shows a live reference to the object — not a snapshot. If the object is modified after the log call, the console may show the updated state.
const user = { name: "Alice" };
console.log(user); // displays: { name: "Alice" }
user.name = "Bob"; // modify after logging
// The console may now show { name: "Bob" } when you expand the logged object!
To log a true snapshot of an object at that moment, use console.log(JSON.stringify(user)) or spread it: console.log({ ...user }).
Mistake 2: Reading error messages only partially
The error message tells you the type and reason. The stack trace below it tells you which file and line caused it. Beginners often read the first line and stop, missing the file and line number.
TypeError: Cannot read properties of null (reading 'textContent')
at updateBanner (app.js:42:15)
at form.submit (app.js:18:3)
Line 42 in app.js is where the bug is. The function updateBanner was called from line 18. Read the full trace to find the exact location.
Mistake 3: Using console.log to confirm code ran, but not confirming the values
Logging a message like "function ran" tells you the function was called but not whether the values inside it were correct.
function processOrder(order) {
console.log("processOrder ran"); // not helpful if order is undefined
const total = order.price * order.quantity; // TypeError if order is null
}
Log the actual values: console.log("processOrder called with:", order). This immediately reveals if order is null, undefined, or missing expected properties.
Quick Recap
console.log,console.warn, andconsole.errorprint values to the browser console with different visual severity levelsconsole.tabledisplays arrays of objects as a readable table;console.groupgroups related logs together- Error messages include the type (
TypeError,ReferenceError,SyntaxError) and a stack trace — read the full trace to find the file and line number - Use
typeof valueto inspect what type a variable holds when it is not what you expect