JavaScript: ES2024 Async, Destructuring and Classes Reference Guide
By DevShelfHub
Modern JS — destructuring, spread, classes, async/await, modules, iterators, the bits of the language you actually use.
96 items
◷ 8 min
ES2024
Async
Iterators
Start hereQuick start · 6 you’ll reach for daily
Destructureconst {a, b} = obj
Spread{...a, x: 1}
Optionaluser?.address?.city
Nullishx ?? fallback
Parallelawait Promise.all([…])
Iteratefor await (const x of stream)
Target versions · paceVersions
Targets:ES2024node ≥ 20browsers: modern evergreen
Snippets pin to ES2024 (Node 20+, all evergreen browsers). Top-level
await, structuredClone,
Array.prototype.toSorted / toReversed,
Object.groupBy / Map.groupBy all
shipped recently. If you target older browsers, transpile with Babel / SWC and check
caniuse.
runtime · package managerSetup
bash
# Node project
npm init -y
echo '{"type":"module"}' > package.json # opt into ESM
# Run a script
node src/index.js # ESM, top-level await OK in 20+
node --watch src/index.js # built-in watch mode (Node 18+)
# Or pick a faster runtime
bun run src/index.js # bun: native JS/TS + bundler + test runner
deno run src/index.js # deno: secure-by-default, web APIs
# Package manager picks
npm install lodash-es # widest compatibility
pnpm add lodash-es # fastest in monorepos
bun add lodash-es # fastest single-package
# Format + lint
npx eslint . --fix
npx prettier --write .
AbortController + exponential backoff + bounded parallelism. The four-tool kit you reach for whenever
you’re wrangling an external API.
javascript
// Tiny rate-limited fetcher: AbortController + retry + concurrency limit.
async function fetchJSON(url, { retries = 2, timeout = 5_000 } = {}) {
for (let attempt = 0; attempt <= retries; attempt++) {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), timeout);
try {
const res = await fetch(url, { signal: ctrl.signal });
if (!res.ok) throw new Error(`${res.status} ${url}`);
return await res.json();
} catch (err) {
if (attempt === retries) throw err;
await new Promise(r => setTimeout(r, 2 ** attempt * 200)); // backoff
} finally {
clearTimeout(t);
}
}
}
async function mapLimit(items, limit, fn) {
const out = new Array(items.length);
let i = 0;
await Promise.all(
Array.from({ length: limit }, async () => {
while (i < items.length) {
const idx = i++;
out[idx] = await fn(items[idx], idx);
}
}),
);
return out;
}
const urls = ["/a", "/b", "/c", "/d", "/e"];
const results = await mapLimit(urls, 3, fetchJSON);
console.log(results);
Best practiceGood to know
Use the non-mutating Array methods.toSorted / toReversed /
toSpliced were added precisely so you stop accidentally mutating shared
state. Default to them.
structuredClone beats JSON.parse(JSON.stringify(…)).
Handles Maps, Sets, Dates, typed arrays, cycles — and is faster. The JSON round-trip silently drops
undefined, functions, and symbols.
Always pass an AbortSignal to fetch.
Without one, a hung network call holds the whole pipeline. AbortSignal.timeout(ms)
is one line.
Common trapsWatch out for
Arrow functions don’t bind their own this.
Great for callbacks; wrong for methods you want to call with a different receiver. Mixing the two is the
#1 “this is undefined” bug.
Spread is shallow.{...a} copies one level. Nested objects still share references — mutate
one, the other sees it. Reach for structuredClone or an immutable lib.
Forgetting await inside a loop.[1,2,3].map(async …) returns Promises, not results. Use
Promise.all(arr.map(async …)) or a for loop with
await.
JavaScript is the language of the web — it runs in every browser and, via Node.js or Deno, on the server. It powers interactive frontends (React, Vue, Svelte), REST and GraphQL APIs, CLI tools, and serverless functions. ES2024 and Node 20+ are the current baseline.
What is the difference between let, const, and var in JavaScript?
var is function-scoped and hoisted, which causes surprising bugs. let and const are block-scoped and are the modern replacements. Use const for values that are never reassigned (including object and array references); use let when the binding must change.
How does async/await work in JavaScript?
async/await is syntactic sugar over Promises. An async function always returns a Promise; await pauses execution inside the function until the awaited Promise resolves or rejects. Wrap await calls in try/catch to handle errors, or attach .catch() to the returned Promise.
What is optional chaining in JavaScript?
Optional chaining (?.) short-circuits to undefined instead of throwing a TypeError when accessing a property on null or undefined. user?.address?.city returns undefined safely if user or address is null. Use it with the nullish coalescing operator (??) to provide a fallback.
What is the difference between == and === in JavaScript?
=== (strict equality) checks value and type with no coercion: 0 === false is false. == (loose equality) coerces types before comparing: 0 == false is true. Always use === unless you deliberately want type coercion — loose equality is a common source of bugs.