mirror of
https://github.com/duthaho/claudekit.git
synced 2026-09-04 01:00:51 +03:00
feat: adding new skills, including testing patterns and methodologies, along with bundled resources for better usability.
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
# Modern JavaScript Patterns Quick Reference
|
||||
|
||||
> ES2020+ patterns. All examples work in current Node.js (18+) and modern browsers.
|
||||
|
||||
## Destructuring Tricks
|
||||
|
||||
```javascript
|
||||
// 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 (?.)
|
||||
|
||||
```javascript
|
||||
// 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 (||)
|
||||
|
||||
```javascript
|
||||
// ?? 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
|
||||
|
||||
```javascript
|
||||
// ??= 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)
|
||||
|
||||
```javascript
|
||||
// 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
|
||||
|
||||
```javascript
|
||||
// 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
|
||||
|
||||
```javascript
|
||||
// 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
|
||||
|
||||
```javascript
|
||||
// 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
|
||||
|
||||
```javascript
|
||||
// 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) |
|
||||
Reference in New Issue
Block a user