| name | modern-javascript-patterns |
| description | Apply modern JavaScript patterns including async/await, modules, iterators, generators, and functional composition. Use when the user needs ES6+ refactors, cleaner JavaScript structure, or performance-oriented modern syntax. |
Modern JavaScript Patterns
Comprehensive guide for mastering modern JavaScript (ES6+) features, functional programming patterns, and best practices for writing clean, maintainable, and performant code.
When to Use
- Refactoring legacy JavaScript to modern syntax
- Implementing functional programming patterns
- Optimizing JavaScript performance
- Writing maintainable and readable code
- Working with asynchronous operations
- Building modern web applications
- Migrating from callbacks to Promises/async-await
- Implementing data transformation pipelines
ES6+ Core Features
1. Arrow Functions
Syntax and Use Cases:
function add(a, b) {
return a + b;
}
const add = (a, b) => a + b;
const double = (x) => x * 2;
const getRandom = () => Math.random();
const processUser = (user) => {
const normalized = user.name.toLowerCase();
return { ...user, name: normalized };
};
const createUser = (name, age) => ({ name, age });
Lexical 'this' Binding:
class Counter {
constructor() {
this.count = 0;
}
increment = () => {
this.count++;
};
incrementTraditional() {
setTimeout(function () {
this.count++;
}, 1000);
}
incrementArrow() {
setTimeout(() => {
this.count++;
}, 1000);
}
}
2. Destructuring
Object Destructuring:
const user = {
id: 1,
name: "John Doe",
email: "user@domain.test",
address: {
city: "New York",
country: "USA",
},
};
const { name, email } = user;
const { name: userName, email: userEmail } = user;
const { age = 25 } = user;
const {
address: { city, country },
} = user;
const { id, ...userWithoutId } = user;
function greet({ name, age = 18 }) {
console.log(`Hello ${name}, you are ${age}`);
}
greet(user);
Array Destructuring:
const numbers = [1, 2, 3, 4, 5];
const [first, second] = numbers;
const [, , third] = numbers;
const [head, ...tail] = numbers;
let a = 1,
b = 2;
[a, b] = [b, a];
function getCoordinates() {
return [10, 20];
}
const [x, y] = getCoordinates();
const [one, two, three = 0] = [1, 2];
3. Spread and Rest Operators
Spread Operator:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
const defaults = { theme: "dark", lang: "en" };
const userPrefs = { theme: "light" };
const settings = { ...defaults, ...userPrefs };
const numbers = [1, 2, 3];
Math.max(...numbers);
const copy = [...arr1];
const objCopy = { ...user };
const newArr = [...arr1, 4, 5];
const newObj = { ...user, age: 30 };
Rest Parameters:
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
sum(1, 2, 3, 4, 5);
function greet(greeting, ...names) {
return `${greeting} ${names.join(", ")}`;
}
greet("Hello", "John", "Jane", "Bob");
const { id, ...userData } = user;
const [first, ...rest] = [1, 2, 3, 4, 5];
4. Template Literals
const name = "John";
const greeting = `Hello, ${name}!`;
const html = `
<div>
<h1>${title}</h1>
<p>${content}</p>
</div>
`;
const price = 19.99;
const total = `Total: $${(price * 1.2).toFixed(2)}`;
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i] || "";
return result + str + `<mark>${value}</mark>`;
}, "");
}
const name = "John";
const age = 30;
const html = highlight`Name: ${name}, Age: ${age}`;
5. Enhanced Object Literals
const name = "John";
const age = 30;
const user = { name, age };
const calculator = {
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
},
};
const field = "email";
const user = {
name: "John",
[field]: "user@domain.test",
[`get${field.charAt(0).toUpperCase()}${field.slice(1)}`]() {
return this[field];
},
};
const createUser = (name, ...props) => {
return props.reduce(
(user, [key, value]) => ({
...user,
[key]: value,
}),
{ name },
);
};
const user = createUser("John", ["age", 30], ["email", "user@domain.test"]);
Asynchronous Patterns
1. Promises
Creating and Using Promises:
const fetchUser = (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id, name: "John" });
} else {
reject(new Error("Invalid ID"));
}
}, 1000);
});
};
fetchUser(1)
.then((user) => console.log(user))
.catch((error) => console.error(error))
.finally(() => console.log("Done"));
fetchUser(1)
.then((user) => fetchUserPosts(user.id))
.then((posts) => processPosts(posts))
.( .(result))
.( .(error));
Promise Combinators:
const promises = [fetchUser(1), fetchUser(2), fetchUser(3)];
Promise.all(promises)
.then((users) => console.log(users))
.catch((error) => console.error("At least one failed:", error));
Promise.allSettled(promises).then((results) => {
results.forEach((result) => {
if (result.status === "fulfilled") {
console.log("Success:", result.value);
} else {
console.log("Error:", result.reason);
}
});
});
Promise.race(promises)
.then((winner) => console.(, winner))
.( .(error));
.(promises)
.( .(, first))
.( .(, error));
2. Async/Await
Basic Usage:
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user;
}
async function getUserData(id) {
try {
const user = await fetchUser(id);
const posts = await fetchUserPosts(user.id);
return { user, posts };
} catch (error) {
console.error("Error fetching data:", error);
throw error;
}
}
async function sequential() {
const user1 = await fetchUser(1);
const user2 = await fetchUser(2);
return [user1, user2];
}
async function () {
[user1, user2] = .([(), ()]);
[user1, user2];
}
Advanced Patterns:
(async () => {
const result = await someAsyncOperation();
console.log(result);
})();
async function processUsers(userIds) {
for (const id of userIds) {
const user = await fetchUser(id);
await processUser(user);
}
}
const config = await fetch("/config.json").then((r) => r.json());
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url);
} catch (error) {
if (i === retries - 1) throw error;
await new Promise((resolve) => (resolve, * (i + )));
}
}
}
() {
timeout = (
( ( ()), ms),
);
.([promise, timeout]);
}
Functional Programming Patterns
Functional programming in JavaScript centers on pure functions, immutability, and composable transformations.
Key topics covered in references/advanced-patterns.md:
- Array methods —
map, filter, reduce, find, findIndex, some, every, flatMap, Array.from
- Higher-order functions — custom
forEach/map/filter, currying, partial application, memoization
- Composition and piping —
compose/pipe utilities with practical data transformation examples
- Pure functions and immutability — immutable array/object operations, deep cloning with
structuredClone
Modern Class Features
ES2022 classes support private fields (#field), static fields, getters/setters, and private methods. See references/advanced-patterns.md for a full example with inheritance.
Modules (ES6)
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default function multiply(a, b) { return a * b; }
import multiply, { PI, add } from "./math.js";
const { add } = await import("./math.js");
For re-exports, namespace imports, and conditional dynamic loading see references/advanced-patterns.md.
Iterators and Generators
Generators (function*) and async generators (async function*) enable lazy sequences and async pagination. See references/advanced-patterns.md for custom iterator, range generator, fibonacci, and for await...of examples.
Modern Operators
const city = user?.address?.city;
const result = obj.method?.();
const value = null ?? "default";
const zero = 0 ?? "default";
a ??= "default";
obj.count ||= 1;
obj.count &&= 2;
Performance Optimization
See references/advanced-patterns.md for debounce, throttle, and lazy evaluation with generators.
Best Practices
- Use const by default: Only use let when reassignment is needed
- Prefer arrow functions: Especially for callbacks
- Use template literals: Instead of string concatenation
- Destructure objects and arrays: For cleaner code
- Use async/await: Instead of Promise chains
- Avoid mutating data: Use spread operator and array methods
- Use optional chaining: Prevent "Cannot read property of undefined"
- Use nullish coalescing: For default values
- Prefer array methods: Over traditional loops
- Use modules: For better code organization
- Write pure functions: Easier to test and reason about
- Use meaningful variable names: Self-documenting code
- Keep functions small: Single responsibility principle
- Handle errors properly: Use try/catch with async/await
- Use strict mode:
'use strict' for better error catching
For common pitfalls (this binding, promise anti-patterns, memory leaks), see references/advanced-patterns.md.
Overview
Use this skill for the capability described in this document.
Core Workflow
Follow the primary workflow, commands, and decision points documented in the sections below.
Examples
Use the examples and snippets already present in this document whenever they apply to the task.
References
Use any linked scripts, assets, reference files, and companion resources mentioned in this document.