1---2name: toolchains-javascript-core3description: "JavaScript ES2024+ and Node.js 22+ core patterns for minimalism, efficiency, code reuse, and performance"4version: "1.0.0"5category: toolchains-javascript6tags: [javascript, nodejs, patterns, performance, minimalism, efficiency]7effort: medium8---910# JavaScript Core Patterns (ES2024+ / Node.js 22+)1112## Quick Start1314- `const` by default, `let` only for reassignment, never `var`15- Optional chaining `?.` and nullish coalescing `??` over manual null guards16- ESM `import`/`export` exclusively — treat `require` as legacy17- `structuredClone()` over `JSON.parse(JSON.stringify())`18- `node:` prefix for all built-in modules: `import fs from 'node:fs'`1920## Minimalism Patterns2122- Use `?.` for nested property access; use `??` for defaults (not `||` — it falsely triggers on `0`, `""`, `false`)23- Destructure at point of use to reduce intermediate variables and clarify intent24- Use rest parameters `...args` over `arguments`; use spread over `Object.assign` or `concat`25- Declare private class fields with `#prefix`; never use underscore conventions to simulate privacy26- Use `using` declarations for explicit resource management — resources with `[Symbol.dispose]()` auto-cleanup on scope exit27- Use `await using` for async resources (`[Symbol.asyncDispose]()`); eliminates try/finally for streams and connections28- Use `DisposableStack` / `AsyncDisposableStack` when resource acquisition is conditional or multiple disposables need aggregation2930## Efficiency Patterns3132- Attach event listeners on a parent element (event delegation); use `event.target.closest()` to identify source33- Batch DOM mutations into a `DocumentFragment` before appending to the live DOM34- Use `requestAnimationFrame` for all visual/DOM updates; never modify DOM in `setTimeout` for animations35- Use `requestIdleCallback` (or `scheduler.postTask({ priority: 'background' })`) for non-urgent background work36- Use `IntersectionObserver` for lazy loading, infinite scroll, and visibility detection — never poll scroll position37- Call `observer.unobserve(el)` or `observer.disconnect()` when observation is no longer needed38- Use `AbortController` to batch-remove multiple event listeners with a single `abort()` call on cleanup39- Use `WeakMap` to associate metadata with DOM elements; entries auto-clean when elements are garbage-collected4041## Code Reuse4243- Use ESM `import`/`export` exclusively; use dynamic `import()` for code splitting and lazy-loading44- Build reusable UI with Web Components (Custom Elements + Shadow DOM + HTML Templates) — framework-agnostic45- Name custom elements in kebab-case with a hyphen (`my-button`) to avoid collision with native HTML tags46- Use Declarative Shadow DOM (`<template shadowrootmode="open">`) for server-rendered Web Components47- Use `:host` and CSS custom properties as the theming API for Web Components; keep internal styles encapsulated48- Use `Proxy` for cross-cutting concerns (validation, logging, access control) without modifying target objects49- Use `Reflect` methods inside Proxy traps to forward default behavior — never re-implement native semantics50- Export pure functions and compose them; prefer composition over class inheritance for business logic5152## Modern JS (ES2024+ / Node.js 22+)5354- `structuredClone()` — deep copy with support for `Date`, `Map`, `Set`, `ArrayBuffer`, circular refs55- `Object.groupBy()` / `Map.groupBy()` — replace reduce-based grouping patterns56- `Set` methods: `.union()`, `.intersection()`, `.difference()`, `.symmetricDifference()`, `.isSubsetOf()`57- Immutable array methods: `toSorted()`, `toReversed()`, `toSpliced()`, `with()` — no source mutation58- Iterator helpers: `.map()`, `.filter()`, `.take()`, `.drop()`, `.toArray()` directly on iterators (lazy)59- `Iterator.from(iterable)` — create iterator objects from any iterable60- `Promise.withResolvers()` — extract resolve/reject without wrapping in a constructor callback61- `Promise.try(fn)` — unify sync and async error handling into a single promise chain62- `RegExp.escape(str)` — safely interpolate user input into regular expressions63- Import attributes: `import data from './data.json' with { type: 'json' }` for type-safe module imports64- Temporal API (`Temporal.PlainDate`, `Temporal.ZonedDateTime`, `Temporal.Duration`): use `temporal-polyfill` until native support lands6566## Node.js 22+ Performance Patterns6768- Always use `node:` prefix: `import { readFile } from 'node:fs/promises'`69- Use `import.meta.dirname` and `import.meta.filename` instead of `__dirname`/`__filename` in ESM70- Use built-in `fetch()` for HTTP; combine with `AbortController` for timeouts and cancellation71- Use `--env-file=.env` or `process.loadEnvFile()` to load env vars; eliminates the `dotenv` dependency72- Use `--watch` for dev auto-restart instead of `nodemon`73- Use `node:test` runner for testing; eliminates Jest/Mocha for most projects74- Use Web Crypto API (`globalThis.crypto`) for cryptographic operations aligned with browser standards75- Run TypeScript directly with `node index.ts` (strip-types) for scripts and prototyping7677## DOM Performance7879- Batch reads then writes — never interleave reads and writes (forces layout thrashing)80- Use `IntersectionObserver` over scroll listeners; use `MutationObserver` over DOM polling81- Use `ResizeObserver` to respond to element size changes without window resize listeners82- Event delegation on parent containers scales to thousands of dynamic children at zero extra listener cost83- Virtual scrolling for long lists: render only visible items, translate with `transform: translateY`84- Prefer CSS for animation, container queries, `:has()`, and scroll-driven effects over JavaScript equivalents8586## Testing8788- Use `node:test` with `describe`/`it` blocks; supports nested suites and `before`/`after` hooks89- Mock with `context.mock.fn()` (spy) and `context.mock.method(obj, 'name')` for object methods90- Mock timers: `context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })`; advance with `.tick(ms)`91- Coverage: `node --test --experimental-test-coverage` — no `nyc` or `c8` needed92- Watch mode: `node --test --watch` for rapid feedback93- For browser and E2E: Playwright — cross-browser, network interception, screenshot/video94- Property-based testing: fast-check for discovering edge cases in pure functions95- Vitest for projects already using Vite; Jest API-compatible with faster parallel execution9697## Anti-Patterns9899- Never use `var` — hoisting bugs and scope leaks that `const`/`let` prevent100- Never use `JSON.parse(JSON.stringify())` for deep cloning — use `structuredClone()`101- Never poll scroll position with `scroll` listeners — use `IntersectionObserver`102- Never import Lodash, Moment.js, jQuery, or RequireJS for new code — native ES2024+ covers core use cases103- Never use `arguments` object — use rest parameters `...args` which produce a real Array104- Never write manual null-check chains — use `?.` and `??`105- Never modify `Object.prototype` or prototypes you do not own — causes naming collisions106- Never use `eval()` — security risk and performance penalty107- Never add individual listeners to thousands of child elements — use event delegation108- Never attach closures referencing large objects to long-lived event listeners without cleanup — memory leak