mirror of
https://github.com/duthaho/claudekit.git
synced 2026-06-10 20:24:57 +03:00
5.8 KiB
5.8 KiB
Modern JavaScript Patterns Quick Reference
ES2020+ patterns. All examples work in current Node.js (18+) and modern browsers.
Destructuring Tricks
// Nested destructuring with rename and default
const { data: { users: members = [] } = {} } = response;
// Array destructuring: skip elements
const [first, , third] = [1, 2, 3];
// Swap variables
[a, b] = [b, a];
// Rest in both arrays and objects
const { id, ...rest } = user;
const [head, ...tail] = items;
// Destructure function parameters
function draw({ x = 0, y = 0, color = "black" } = {}) { /* ... */ }
// Dynamic property destructuring
const key = "name";
const { [key]: value } = { name: "Alice" }; // value = "Alice"
// Destructure from iterables
const [a, b] = new Map([["a", 1], ["b", 2]]);
Optional Chaining (?.)
// Property access
const city = user?.address?.city;
// Method call (only calls if method exists)
const result = api?.getData?.();
// Bracket notation
const val = obj?.["dynamic-key"];
// Array index
const first = arr?.[0];
// Combine with nullish coalescing
const name = user?.profile?.name ?? "Anonymous";
// Short-circuit: stops evaluating after first nullish
const len = response?.data?.items?.length; // undefined if any is nullish
Nullish Coalescing (??) vs OR (||)
// ?? only triggers on null/undefined (NOT 0, "", false)
0 ?? "fallback" // 0
"" ?? "fallback" // ""
null ?? "fallback" // "fallback"
// || triggers on any falsy value
0 || "fallback" // "fallback"
"" || "fallback" // "fallback"
null || "fallback" // "fallback"
// Use ?? for values where 0/empty string are valid
const port = config.port ?? 3000;
const title = config.title ?? "Untitled";
Logical Assignment Operators
// ??= assigns only if current value is null/undefined
user.name ??= "Anonymous";
// Equivalent: user.name = user.name ?? "Anonymous"
// ||= assigns if current value is falsy
opts.verbose ||= false;
// Equivalent: opts.verbose = opts.verbose || false
// &&= assigns only if current value is truthy
user.token &&= encrypt(user.token);
// Equivalent: user.token = user.token && encrypt(user.token)
structuredClone (Deep Copy)
// Deep clone objects, arrays, Maps, Sets, Dates, RegExp, etc.
const original = { date: new Date(), nested: { arr: [1, 2] } };
const clone = structuredClone(original);
clone.nested.arr.push(3); // original not affected
// Works with circular references
const obj = { self: null };
obj.self = obj;
const copy = structuredClone(obj); // OK
// Does NOT clone: functions, DOM nodes, symbols, prototype chain
// Throws on: functions, Error objects (in some engines)
Proxy
// Validation proxy
const validated = new Proxy({}, {
set(target, prop, value) {
if (prop === "age" && (typeof value !== "number" || value < 0)) {
throw new TypeError("Age must be a non-negative number");
}
target[prop] = value;
return true;
}
});
// Read-only proxy
function readonly(target) {
return new Proxy(target, {
set() { throw new Error("Read-only object"); },
deleteProperty() { throw new Error("Read-only object"); }
});
}
// Default values proxy
function withDefaults(target, defaults) {
return new Proxy(target, {
get(obj, prop) {
return prop in obj ? obj[prop] : defaults[prop];
}
});
}
const config = withDefaults({}, { theme: "dark", lang: "en" });
config.theme; // "dark"
// Logging / observation proxy
function observable(target, onChange) {
return new Proxy(target, {
set(obj, prop, value) {
const old = obj[prop];
obj[prop] = value;
onChange(prop, old, value);
return true;
}
});
}
Generators
// Basic generator
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
for (const n of range(0, 10, 2)) { /* 0, 2, 4, 6, 8 */ }
// Infinite sequence
function* ids() {
let id = 0;
while (true) yield id++;
}
const gen = ids();
gen.next().value; // 0
gen.next().value; // 1
// Delegate to another generator
function* concat(...iterables) {
for (const it of iterables) {
yield* it;
}
}
// Two-way communication
function* stateMachine() {
let input;
while (true) {
input = yield `received: ${input}`;
}
}
const sm = stateMachine();
sm.next(); // { value: "received: undefined" }
sm.next("hello"); // { value: "received: hello" }
Async Iterators
// for-await-of
async function processStream(stream) {
for await (const chunk of stream) {
console.log(chunk);
}
}
// Async generator
async function* fetchPages(url) {
let page = 1;
while (true) {
const res = await fetch(`${url}?page=${page}`);
const data = await res.json();
if (data.items.length === 0) return;
yield data.items;
page++;
}
}
for await (const items of fetchPages("/api/users")) {
console.log(items);
}
Other Modern Patterns
// Object.groupBy (ES2024)
const grouped = Object.groupBy(users, u => u.role);
// at() - negative indexing
[1, 2, 3].at(-1); // 3
// Object.hasOwn (replaces hasOwnProperty)
Object.hasOwn(obj, "key"); // true/false
// Error cause chaining
throw new Error("DB failed", { cause: originalError });
// AbortSignal.timeout (built-in timeout)
fetch(url, { signal: AbortSignal.timeout(5000) });
// using keyword (explicit resource management, ES2024+)
{ using handle = openFile("data.txt"); } // auto-disposed at block exit
Promise Combinators
| Method | Settles when | Returns |
|---|---|---|
Promise.all(ps) |
All fulfill or one rejects | Array of values |
Promise.allSettled(ps) |
All settle | Array of {status, value/reason} |
Promise.race(ps) |
First settles | First value or rejection |
Promise.any(ps) |
First fulfills | First value (AggregateError if all reject) |