Core Concepts
2 min readRapid overview
JavaScript Core Concepts
Modern JavaScript for frontend work relies on understanding the runtime, language mechanics, and browser APIs. This guide focuses on concepts you will apply before adding frameworks.
Execution model
- Call stack + heap: Functions execute on the call stack; objects/closures live on the heap. Avoid unbounded recursion and large synchronous work that blocks rendering.
- Event loop: Macrotasks (timers, I/O) and microtasks (promises) interleave. Prefer microtasks for post-render follow-ups, and batch DOM reads/writes to avoid layout thrash.
- Concurrency model: Single-threaded with cooperative multitasking. Use Web Workers for CPU-bound tasks; keep UI thread free.
Values, types, and coercion
- Primitives vs objects:
string,number,boolean,bigint,symbol,undefined,nullvs object/function wrappers. - Equality: Prefer
===; know how==coerces. Avoid implicit coercion in critical paths. - Immutability: Favor pure functions and immutable updates (e.g., spread,
Array.prototype.map) to simplify reasoning and compatibility with React/Angular change detection.
Functions, scope, and closure
- Lexical scope: Variables resolve from the declaration environment (
let/constblock scope,varfunction scope). - Closures: Functions capture surrounding bindings; key for callbacks, event handlers, and module patterns.
thisbinding: Depends on call-site. Use arrow functions to avoid rebinding, or explicitcall/apply/bindwhen needed.
Objects, prototypes, and classes
- Prototype chain: Property lookup walks prototypes. Use
Object.create(null)for pure dictionaries to avoid inherited keys. - Classes: Sugar over prototypes. Keep constructors side-effect free; use private fields for encapsulation when supported.
- Composition over inheritance: Prefer small utilities and factory functions to deep class hierarchies.
Modules and packaging
- ESM first: Use
import/exportwith bundlers (Vite, Webpack, esbuild). Avoid mixing ESM and CommonJS in the same file. - Tree shaking: Export named bindings; avoid dynamic requires to enable dead code elimination.
- Environment boundaries: Browser vs Node — know what needs polyfills and how to lazy-load optional features.
Async and networking
- Promises and async/await: Always
returnpromises; wrap parallel work withPromise.alland handle rejection paths. - Fetch patterns: Centralize fetch helpers for auth/errors/retries; treat
response.okas the gate for success. - Cancellation: Use
AbortControllerfor fetch and long-running tasks.
DOM, events, and performance
- DOM access: Prefer query selectors scoped to containers; avoid forced synchronous layout (
offsetWidthafter mutations) without batching. - Events: Delegate where possible; respect accessibility semantics (keyboard + pointer).
- Performance: Measure with Performance APIs; defer non-critical work with
requestIdleCallback/setTimeout.
Error handling and resiliency
- Errors vs rejections: Normalize error handling paths; attach context and user-friendly messages.
- Boundary patterns: Use guard clauses and feature detection; fail fast on unsupported APIs.
Testing and quality
- Linting/formatting: ESLint + Prettier baselines; enforce
no-floating-promises,eqeqeq, and import hygiene. - Unit/integration tests: Favor fast, deterministic tests; mock boundaries (network, time) and assert user-visible outcomes.
Interview-ready snippets
- Debounce vs throttle implementations and when to prefer each.
- Promise utilities: timeout wrapper, retry with backoff, and pooled concurrency executor.
- Event loop tracing: predict log order for
setTimeout,Promise.resolve, and synchronous logs.