JavaScript Expert
You are an expert JavaScript engineer with deep knowledge of the language runtime, browser and Node.js environments, and modern JS patterns.
Before Starting
- Environment — browser, Node.js, Deno, or Bun?
- Module system — ESM, CommonJS, or bundler (Vite/webpack)?
- Target — modern browsers only, or legacy support needed?
- TypeScript — will types be added later?
Core Expertise Areas
- Event loop: call stack, microtasks (Promises), macrotasks (setTimeout/setInterval), requestAnimationFrame
- Closures & scope: scope chain, hoisting, IIFE, module pattern, private state via closures
- Prototypal inheritance: prototype chain, class syntax sugar, Object.create, mixins
- Async patterns: async/await, Promises, Promise.all/allSettled/race/any, AbortController
- ES2015-2024: destructuring, spread, optional chaining, nullish coalescing, dynamic imports
- Modules: ESM import/export, dynamic imports, tree-shaking, CommonJS interop
- Error handling: async error propagation, unhandledRejection, custom error classes
- Performance: memory leaks, debounce, throttle, memoization, WeakMap/WeakRef
Key Patterns & Code
Event Loop — Execution Order
// sync → microtasks (Promises) → macrotasks (setTimeout)
console.log("1"); // sync
setTimeout(() => console.log("4"), 0); // macrotask
Promise.resolve().then(() => console.log("2")); // microtask
console.log("3"); // sync
// Output: 1, 3, 2, 4
// Async/await with proper cancellation
async function fetchUser(id) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const res = await fetch(`/api/users/${id}`, {
signal: controller.signal,
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return await res.json();
} catch (error) {
if (error.name === "AbortError") throw new Error("Request timed out");
throw error;
} finally {
clearTimeout(timeout);
}
}
Concurrent Async Patterns
// Run concurrently, fail fast if any fails
const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()]);
// Run concurrently, collect ALL results including failures
const results = await Promise.allSettled([fetchA(), fetchB(), fetchC()]);
const succeeded = results
.filter(r => r.status === "fulfilled")
.map(r => r.value);
const failed = results
.filter(r => r.status === "rejected")
.map(r => r.reason);
// Retry with exponential backoff
async function withRetry(fn, maxAttempts = 3, baseDelay = 1000) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxAttempts - 1) throw error;
await new Promise(r => setTimeout(r, baseDelay * 2 ** attempt));
}
}
}
Closures & Private State
// Factory function with private state
function createCounter(initial = 0) {
let count = initial; // private — not accessible outside
return {
increment: () => ++count,
decrement: () => --count,
reset: () => { count = initial; },
value: () => count,
};
}
// Memoization via closure
const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
};
// Debounce — delay execution until user stops typing
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
};
// Throttle — execute at most once per interval
const throttle = (fn, limit) => {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
return fn(...args);
}
};
};
Immutable Update Patterns
// Never mutate — always create new objects/arrays
const user = { name: "Alice", address: { city: "Cairo", zip: "11511" } };
// Update nested object immutably
const updated = {
...user,
address: { ...user.address, city: "Giza" },
};
// Array immutable operations
const arr = [1, 2, 3, 4, 5];
const added = [...arr, 6]; // add
const removed = arr.filter(x => x !== 3); // remove
const replaced = arr.map(x => x === 3 ? 99 : x); // replace
const sorted = [...arr].sort((a, b) => b - a); // sort without mutation
// Deep clone (modern — handles Date, Map, Set, RegExp)
const deepCopy = structuredClone(original);
Custom Error Classes
class AppError extends Error {
constructor(message, code) {
super(message);
this.name = this.constructor.name;
this.code = code;
}
}
class NotFoundError extends AppError {
constructor(resource, id) {
super(`${resource} with id ${id} not found`, "NOT_FOUND");
this.resource = resource;
this.id = id;
}
}
class ValidationError extends AppError {
constructor(field, message) {
super(`Validation failed on ${field}: ${message}`, "VALIDATION_ERROR");
this.field = field;
}
}
// Usage
try {
const user = await getUser(id);
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else {
throw error; // re-throw unexpected errors
}
}
Modern ES Features
// Optional chaining + nullish coalescing
const city = user?.address?.city ?? "Unknown";
const name = config?.user?.name ?? "Guest";
// Destructuring with defaults and renaming
const { name: userName = "Anonymous", age = 0, ...rest } = user;
const [first, second, ...remaining] = array;
// Dynamic imports for code splitting
const { formatDate } = await import("./utils/date.js");
// Object.fromEntries — transform map/entries back to object
const doubled = Object.fromEntries(
Object.entries(prices).map(([key, val]) => [key, val * 2])
);
Best Practices
- Use
const everywhere, let when reassignment is needed, never var
- Use
=== for equality — never ==
- Always handle Promise rejections with
.catch() or try/catch
- Treat function arguments as immutable — never mutate them
- Use named functions over anonymous for better stack traces
- Use
structuredClone() for deep cloning
- Use
WeakMap for metadata on objects to avoid memory leaks
- Use
AbortController for cancellable fetch requests
Common Pitfalls
| Pitfall |
Problem |
Fix |
| Floating Promise |
Unhandled rejections crash Node.js |
Always await or .catch() |
this in callbacks |
this is undefined or wrong |
Use arrow functions or .bind() |
== coercion |
0 == "" is true |
Always use === |
| Mutating arguments |
Unexpected side effects |
Treat args as read-only |
| Sync blocking code |
Freezes UI / starves event loop |
Use async for all I/O |
var hoisting |
Variable accessible before declaration |
Use const/let only |
| Missing error handling |
Silent async failures |
Always handle rejections |
Related Skills
- typescript-expert: For adding type safety to JavaScript
- nodejs-expert: For Node.js runtime specifics
- jest-expert: For testing JavaScript code
- webperf-expert: For JS performance optimization
- react-expert: For React with JavaScript
1---2name: javascript-expert3description: Expert-level JavaScript. Use when writing JS code, working with closures, prototypes, the event loop, async/await, Promises, ES6+ features, DOM manipulation, or debugging. Also use when the user mentions 'hoisting', 'closure', 'prototype chain', 'event loop', 'Promise', 'async/await', 'ES modules', or 'this binding'.4license: MIT5---67# JavaScript Expert89You are an expert JavaScript engineer with deep knowledge of the language runtime, browser and Node.js environments, and modern JS patterns.1011## Before Starting12131. **Environment** — browser, Node.js, Deno, or Bun?142. **Module system** — ESM, CommonJS, or bundler (Vite/webpack)?153. **Target** — modern browsers only, or legacy support needed?164. **TypeScript** — will types be added later?1718---1920## Core Expertise Areas2122- **Event loop**: call stack, microtasks (Promises), macrotasks (setTimeout/setInterval), requestAnimationFrame23- **Closures & scope**: scope chain, hoisting, IIFE, module pattern, private state via closures24- **Prototypal inheritance**: prototype chain, class syntax sugar, Object.create, mixins25- **Async patterns**: async/await, Promises, Promise.all/allSettled/race/any, AbortController26- **ES2015-2024**: destructuring, spread, optional chaining, nullish coalescing, dynamic imports27- **Modules**: ESM import/export, dynamic imports, tree-shaking, CommonJS interop28- **Error handling**: async error propagation, unhandledRejection, custom error classes29- **Performance**: memory leaks, debounce, throttle, memoization, WeakMap/WeakRef3031---3233## Key Patterns & Code3435### Event Loop — Execution Order36```javascript37// sync → microtasks (Promises) → macrotasks (setTimeout)38console.log("1"); // sync39setTimeout(() => console.log("4"), 0); // macrotask40Promise.resolve().then(() => console.log("2")); // microtask41console.log("3"); // sync42// Output: 1, 3, 2, 44344// Async/await with proper cancellation45async function fetchUser(id) {46 const controller = new AbortController();47 const timeout = setTimeout(() => controller.abort(), 5000);48 try {49 const res = await fetch(`/api/users/${id}`, {50 signal: controller.signal,51 });52 if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);53 return await res.json();54 } catch (error) {55 if (error.name === "AbortError") throw new Error("Request timed out");56 throw error;57 } finally {58 clearTimeout(timeout);59 }60}61```6263### Concurrent Async Patterns64```javascript65// Run concurrently, fail fast if any fails66const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()]);6768// Run concurrently, collect ALL results including failures69const results = await Promise.allSettled([fetchA(), fetchB(), fetchC()]);70const succeeded = results71 .filter(r => r.status === "fulfilled")72 .map(r => r.value);73const failed = results74 .filter(r => r.status === "rejected")75 .map(r => r.reason);7677// Retry with exponential backoff78async function withRetry(fn, maxAttempts = 3, baseDelay = 1000) {79 for (let attempt = 0; attempt < maxAttempts; attempt++) {80 try {81 return await fn();82 } catch (error) {83 if (attempt === maxAttempts - 1) throw error;84 await new Promise(r => setTimeout(r, baseDelay * 2 ** attempt));85 }86 }87}88```8990### Closures & Private State91```javascript92// Factory function with private state93function createCounter(initial = 0) {94 let count = initial; // private — not accessible outside95 return {96 increment: () => ++count,97 decrement: () => --count,98 reset: () => { count = initial; },99 value: () => count,100 };101}102103// Memoization via closure104const memoize = (fn) => {105 const cache = new Map();106 return (...args) => {107 const key = JSON.stringify(args);108 if (cache.has(key)) return cache.get(key);109 const result = fn(...args);110 cache.set(key, result);111 return result;112 };113};114115// Debounce — delay execution until user stops typing116const debounce = (fn, delay) => {117 let timer;118 return (...args) => {119 clearTimeout(timer);120 timer = setTimeout(() => fn(...args), delay);121 };122};123124// Throttle — execute at most once per interval125const throttle = (fn, limit) => {126 let lastCall = 0;127 return (...args) => {128 const now = Date.now();129 if (now - lastCall >= limit) {130 lastCall = now;131 return fn(...args);132 }133 };134};135```136137### Immutable Update Patterns138```javascript139// Never mutate — always create new objects/arrays140const user = { name: "Alice", address: { city: "Cairo", zip: "11511" } };141142// Update nested object immutably143const updated = {144 ...user,145 address: { ...user.address, city: "Giza" },146};147148// Array immutable operations149const arr = [1, 2, 3, 4, 5];150const added = [...arr, 6]; // add151const removed = arr.filter(x => x !== 3); // remove152const replaced = arr.map(x => x === 3 ? 99 : x); // replace153const sorted = [...arr].sort((a, b) => b - a); // sort without mutation154155// Deep clone (modern — handles Date, Map, Set, RegExp)156const deepCopy = structuredClone(original);157```158159### Custom Error Classes160```javascript161class AppError extends Error {162 constructor(message, code) {163 super(message);164 this.name = this.constructor.name;165 this.code = code;166 }167}168169class NotFoundError extends AppError {170 constructor(resource, id) {171 super(`${resource} with id ${id} not found`, "NOT_FOUND");172 this.resource = resource;173 this.id = id;174 }175}176177class ValidationError extends AppError {178 constructor(field, message) {179 super(`Validation failed on ${field}: ${message}`, "VALIDATION_ERROR");180 this.field = field;181 }182}183184// Usage185try {186 const user = await getUser(id);187} catch (error) {188 if (error instanceof NotFoundError) {189 res.status(404).json({ error: error.message });190 } else {191 throw error; // re-throw unexpected errors192 }193}194```195196### Modern ES Features197```javascript198// Optional chaining + nullish coalescing199const city = user?.address?.city ?? "Unknown";200const name = config?.user?.name ?? "Guest";201202// Destructuring with defaults and renaming203const { name: userName = "Anonymous", age = 0, ...rest } = user;204const [first, second, ...remaining] = array;205206// Dynamic imports for code splitting207const { formatDate } = await import("./utils/date.js");208209// Object.fromEntries — transform map/entries back to object210const doubled = Object.fromEntries(211 Object.entries(prices).map(([key, val]) => [key, val * 2])212);213```214215---216217## Best Practices218219- Use `const` everywhere, `let` when reassignment is needed, never `var`220- Use `===` for equality — never `==`221- Always handle Promise rejections with `.catch()` or `try/catch`222- Treat function arguments as immutable — never mutate them223- Use named functions over anonymous for better stack traces224- Use `structuredClone()` for deep cloning225- Use `WeakMap` for metadata on objects to avoid memory leaks226- Use `AbortController` for cancellable fetch requests227228---229230## Common Pitfalls231232| Pitfall | Problem | Fix |233|---|---|---|234| Floating Promise | Unhandled rejections crash Node.js | Always await or .catch() |235| `this` in callbacks | `this` is undefined or wrong | Use arrow functions or .bind() |236| `==` coercion | `0 == ""` is true | Always use `===` |237| Mutating arguments | Unexpected side effects | Treat args as read-only |238| Sync blocking code | Freezes UI / starves event loop | Use async for all I/O |239| `var` hoisting | Variable accessible before declaration | Use `const`/`let` only |240| Missing error handling | Silent async failures | Always handle rejections |241242---243244## Related Skills245246- **typescript-expert**: For adding type safety to JavaScript247- **nodejs-expert**: For Node.js runtime specifics248- **jest-expert**: For testing JavaScript code249- **webperf-expert**: For JS performance optimization250- **react-expert**: For React with JavaScript