JavaScript runs everywhere — browsers, servers, mobile apps. This complete guide covers all 185 JavaScript tutorials on TheCodeForge, from the basics of the DOM to async/await, React and Node.js.
JavaScript is the only language most developers cannot avoid, which means it is also the language most people learn by accretion — a framework here, a Stack Overflow answer there — without ever assembling the underlying model. That works for a long time and then produces a specific kind of confusion: code that behaves differently than it reads.
Four mechanisms account for nearly all of it. The event loop decides when your code runs. Closures decide what it can see. The this binding rules decide what it is operating on. Prototypes decide where properties come from. Learn those four and the language stops surprising you — including the parts frameworks are built on.
JavaScript runs on one thread with a queue. Synchronous code runs to completion. Then every queued microtask runs — promise callbacks, queueMicrotask — including microtasks queued during that drain. Only then does one macrotask run: a timer callback, an I/O event, a DOM event.
That ordering explains a whole family of behaviours: why setTimeout(fn, 0) runs after every pending promise, why a long synchronous loop freezes the UI completely, and why await inside a loop serialises requests that you probably meant to run concurrently.
Promise.all rejects as soon as any input rejects, and the other requests keep running with nobody listening. When partial success is acceptable — and it usually is for a dashboard or a batch — allSettled is the correct choice.== applies a coercion algorithm that produces results nobody memorises reliably. === compares type and value with no coercion. Use === everywhere, with one idiomatic exception: x == null is a concise check for both null and undefined.
The distinction between those two is worth being precise about, because modern syntax depends on it. undefined means never assigned; null means deliberately empty. ?? falls back only for those two, while || falls back for every falsy value — which is why count || 10 turns a legitimate zero into ten and count ?? 10 does not.
| Expression | Result | Why it matters |
|---|---|---|
0 == '' | true | Coercion to number — the reason to avoid == |
[] == false | true | Array to primitive, then to number |
NaN === NaN | false | Use Number.isNaN, never an equality check |
0 || 10 | 10 | Falsy fallback swallows a valid zero |
0 ?? 10 | 0 | Nullish fallback — almost always what you meant |
typeof null | 'object' | A well-known language bug, kept for compatibility |
A closure is a function that retains access to the variables of the scope it was created in — the variables themselves, not copies of their values. That distinction is the entire explanation for the classic loop puzzle, and for why let fixes it: var creates one function-scoped binding shared by every callback, while let creates a fresh binding per iteration.
Closures are also the mechanism behind most patterns you already use: module privacy, memoisation, debounce and throttle, React hooks holding state between renders, and every callback that remembers something from where it was defined.
ES modules are static: imports are resolved before execution, which is what makes tree shaking possible — a bundler can prove a named export is unused and drop it. CommonJS require is a synchronous function call resolved at runtime, so it cannot be analysed the same way. That single difference explains most bundler behaviour and most of the interop friction between the two.
It also has a practical consequence worth carrying into code review: a default export of a large object, or a barrel file re-exporting an entire library, defeats tree shaking and can put hundreds of kilobytes into a bundle for one function. Named imports from the specific module are not a style preference — they are what lets the bundler remove what you do not use.
const by default, let when you must reassign, var never in new code. const prevents rebinding, not mutation — a const object's properties can still change, which is the point people most often misunderstand.this, promises and array methods appear in every framework's API, and debugging React or Vue without them means every problem looks like framework magic. A week on the fundamentals saves months of confusion.undefined is the absence the language produces — an unassigned variable, a missing property, a function with no return. null is the absence you chose. APIs and databases usually return null; JavaScript itself produces undefined. Use ?? and ?. to handle both without accidentally catching zero or empty string.async means: the function always returns a promise, and await is how you unwrap it. If you are seeing Promise { <pending> }, a caller forgot to await — which is also why a missing await produces silent wrong behaviour rather than an error.Every tutorial starts with a plain-English analogy — then real code, then interview questions.
Browse JavaScript Tutorials →