Errors & tools
The beginner track's last stop — reading what the engine is trying to tell you.
try / catch / finally
try {
JSON.parse("this isn't JSON"); // throws a SyntaxError
} catch (error) {
console.log("caught:", error.message);
} finally {
console.log("finally always runs — success, failure, doesn't matter");
}
try {
throw new Error("inner");
} finally {
console.log("finally ran");
}
Click run — you'll see "finally ran", and then the
error still shows up as uncaught below it. There's no
catch here at all, and finally doesn't stop
the error from propagating — it just guarantees that cleanup code
(closing a connection, hiding a spinner) runs on the way out, whether
the block succeeded or not.
The caught value doesn't have to be named if you don't need it — useful when you only care that something failed:
try {
riskyThing();
} catch { // no (error) — the binding is optional since ES2019
showFallbackUI();
}
Custom errors
Error is a class like any other — extend it to attach
your own data, and instanceof still recognizes the whole
chain.
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = "ValidationError";
this.field = field;
}
}
try {
throw new ValidationError("age must be positive", "age");
} catch (e) {
console.log(e.name, "-", e.message, "- field:", e.field);
console.log("is an Error:", e instanceof Error);
console.log("is a ValidationError:", e instanceof ValidationError);
}
Both instanceof checks come back true —
super(message) wires up the normal Error
machinery (.message, .stack), and the
class ... extends Error keeps the prototype chain intact.
That lets calling code catch broadly (instanceof Error)
or specifically (instanceof ValidationError) depending on
what it actually needs to handle differently.
Reading a stack trace
Every Error carries a .stack string — a
snapshot of every function call that was still active the moment it
was thrown, most-recent first:
Error: Cannot read properties of undefined (reading 'name')
at getDisplayName (utils.js:12:18)
at renderUser (UserCard.js:8:24)
at renderApp (App.js:22:3)
at main (index.js:5:1)
Read it top to bottom, most specific first: line 1 is where
the error actually happened — inside getDisplayName, at
utils.js line 12. Every line under it is a caller, in
order, all the way out to where the whole chain started. The bug is
almost always at or near the top; the rest of the trace is just
"how did we get here."
TypeError reading a property of undefined
tells you where it blew up, not where it went wrong.
The real bug is usually a few frames up — whatever handed
getDisplayName an object it shouldn't have. Read the
whole trace before fixing the top line.
console — more than .log
| Call | For |
|---|---|
console.log(...) | general output |
console.info(...), console.debug(...) | same as log, different icon — some filters hide/show them separately |
console.warn(...) | yellow, doesn't stop anything — a heads-up |
console.error(...) | red, includes a stack trace automatically |
console.table(data) | an array of objects, rendered as an actual table |
console.group(label) / .groupEnd() | indents everything between them — collapsible in DevTools |
console.time(label) / .timeEnd(label) | how long the code between them took |
console.table([
{ name: "Ana", age: 29, role: "admin" },
{ name: "Ravi", age: 34, role: "editor" },
]);
Open your own DevTools console and run that — every object becomes a row, every shared key becomes a column, automatically. It's the single fastest way to eyeball an array of records without writing a loop just to look at it.
DevTools, the short version
- Elements panel — the live DOM tree, editable in place. Change a class or a style here to test an idea before touching the file.
- Console panel — everything above, plus a REPL you can run arbitrary code in, against the actual page that's open.
-
Sources panel — set a real breakpoint by clicking a line
number, or drop
debugger;directly in your code. Either one pauses execution right there, with every variable in scope inspectable. - Network panel — every request the page made, its status, timing, and response — the first place to look when "the data never showed up."
Opens in the editor — write it, run it, and check it against real tests.