Modern Javascript Patterns
Write modern, clean JavaScript with ES6+ patterns and best practices
✨ The solution you've been looking for
Master ES6+ features including async/await, destructuring, spread operators, arrow functions, promises, modules, iterators, generators, and functional programming patterns for writing clean, efficient JavaScript code. Use when refactoring legacy code, implementing modern patterns, or optimizing JavaScript applications.
See It In Action
Interactive preview & real-world examples
AI Conversation Simulator
See how users interact with this skill
User Prompt
Help me refactor this callback-heavy JavaScript code to use async/await and modern array methods
Skill Processing
Analyzing request...
Agent Response
Clean, readable code using modern JavaScript features like destructuring, arrow functions, and Promise-based async patterns
Quick Start (3 Steps)
Get up and running in minutes
Install
claude-code skill install modern-javascript-patterns
claude-code skill install modern-javascript-patternsConfig
First Trigger
@modern-javascript-patterns helpCommands
| Command | Description | Required Args |
|---|---|---|
| @modern-javascript-patterns legacy-code-modernization | Transform outdated JavaScript code using modern ES6+ syntax and patterns | None |
| @modern-javascript-patterns functional-programming-implementation | Apply functional programming concepts for data transformation and processing | None |
| @modern-javascript-patterns asynchronous-operation-optimization | Implement efficient async patterns for API calls and data fetching | None |
Typical Use Cases
Legacy Code Modernization
Transform outdated JavaScript code using modern ES6+ syntax and patterns
Functional Programming Implementation
Apply functional programming concepts for data transformation and processing
Asynchronous Operation Optimization
Implement efficient async patterns for API calls and data fetching
Overview
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 This Skill
- 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:
1// Traditional function
2function add(a, b) {
3 return a + b;
4}
5
6// Arrow function
7const add = (a, b) => a + b;
8
9// Single parameter (parentheses optional)
10const double = (x) => x * 2;
11
12// No parameters
13const getRandom = () => Math.random();
14
15// Multiple statements (need curly braces)
16const processUser = (user) => {
17 const normalized = user.name.toLowerCase();
18 return { ...user, name: normalized };
19};
20
21// Returning objects (wrap in parentheses)
22const createUser = (name, age) => ({ name, age });
Lexical ’this’ Binding:
1class Counter {
2 constructor() {
3 this.count = 0;
4 }
5
6 // Arrow function preserves 'this' context
7 increment = () => {
8 this.count++;
9 };
10
11 // Traditional function loses 'this' in callbacks
12 incrementTraditional() {
13 setTimeout(function () {
14 this.count++; // 'this' is undefined
15 }, 1000);
16 }
17
18 // Arrow function maintains 'this'
19 incrementArrow() {
20 setTimeout(() => {
21 this.count++; // 'this' refers to Counter instance
22 }, 1000);
23 }
24}
2. Destructuring
Object Destructuring:
1const user = {
2 id: 1,
3 name: "John Doe",
4 email: "john@example.com",
5 address: {
6 city: "New York",
7 country: "USA",
8 },
9};
10
11// Basic destructuring
12const { name, email } = user;
13
14// Rename variables
15const { name: userName, email: userEmail } = user;
16
17// Default values
18const { age = 25 } = user;
19
20// Nested destructuring
21const {
22 address: { city, country },
23} = user;
24
25// Rest operator
26const { id, ...userWithoutId } = user;
27
28// Function parameters
29function greet({ name, age = 18 }) {
30 console.log(`Hello ${name}, you are ${age}`);
31}
32greet(user);
Array Destructuring:
1const numbers = [1, 2, 3, 4, 5];
2
3// Basic destructuring
4const [first, second] = numbers;
5
6// Skip elements
7const [, , third] = numbers;
8
9// Rest operator
10const [head, ...tail] = numbers;
11
12// Swapping variables
13let a = 1,
14 b = 2;
15[a, b] = [b, a];
16
17// Function return values
18function getCoordinates() {
19 return [10, 20];
20}
21const [x, y] = getCoordinates();
22
23// Default values
24const [one, two, three = 0] = [1, 2];
3. Spread and Rest Operators
Spread Operator:
1// Array spreading
2const arr1 = [1, 2, 3];
3const arr2 = [4, 5, 6];
4const combined = [...arr1, ...arr2];
5
6// Object spreading
7const defaults = { theme: "dark", lang: "en" };
8const userPrefs = { theme: "light" };
9const settings = { ...defaults, ...userPrefs };
10
11// Function arguments
12const numbers = [1, 2, 3];
13Math.max(...numbers);
14
15// Copying arrays/objects (shallow copy)
16const copy = [...arr1];
17const objCopy = { ...user };
18
19// Adding items immutably
20const newArr = [...arr1, 4, 5];
21const newObj = { ...user, age: 30 };
Rest Parameters:
1// Collect function arguments
2function sum(...numbers) {
3 return numbers.reduce((total, num) => total + num, 0);
4}
5sum(1, 2, 3, 4, 5);
6
7// With regular parameters
8function greet(greeting, ...names) {
9 return `${greeting} ${names.join(", ")}`;
10}
11greet("Hello", "John", "Jane", "Bob");
12
13// Object rest
14const { id, ...userData } = user;
15
16// Array rest
17const [first, ...rest] = [1, 2, 3, 4, 5];
4. Template Literals
1// Basic usage
2const name = "John";
3const greeting = `Hello, ${name}!`;
4
5// Multi-line strings
6const html = `
7 <div>
8 <h1>${title}</h1>
9 <p>${content}</p>
10 </div>
11`;
12
13// Expression evaluation
14const price = 19.99;
15const total = `Total: $${(price * 1.2).toFixed(2)}`;
16
17// Tagged template literals
18function highlight(strings, ...values) {
19 return strings.reduce((result, str, i) => {
20 const value = values[i] || "";
21 return result + str + `<mark>${value}</mark>`;
22 }, "");
23}
24
25const name = "John";
26const age = 30;
27const html = highlight`Name: ${name}, Age: ${age}`;
28// Output: "Name: <mark>John</mark>, Age: <mark>30</mark>"
5. Enhanced Object Literals
1const name = "John";
2const age = 30;
3
4// Shorthand property names
5const user = { name, age };
6
7// Shorthand method names
8const calculator = {
9 add(a, b) {
10 return a + b;
11 },
12 subtract(a, b) {
13 return a - b;
14 },
15};
16
17// Computed property names
18const field = "email";
19const user = {
20 name: "John",
21 [field]: "john@example.com",
22 [`get${field.charAt(0).toUpperCase()}${field.slice(1)}`]() {
23 return this[field];
24 },
25};
26
27// Dynamic property creation
28const createUser = (name, ...props) => {
29 return props.reduce(
30 (user, [key, value]) => ({
31 ...user,
32 [key]: value,
33 }),
34 { name },
35 );
36};
37
38const user = createUser("John", ["age", 30], ["email", "john@example.com"]);
Asynchronous Patterns
1. Promises
Creating and Using Promises:
1// Creating a promise
2const fetchUser = (id) => {
3 return new Promise((resolve, reject) => {
4 setTimeout(() => {
5 if (id > 0) {
6 resolve({ id, name: "John" });
7 } else {
8 reject(new Error("Invalid ID"));
9 }
10 }, 1000);
11 });
12};
13
14// Using promises
15fetchUser(1)
16 .then((user) => console.log(user))
17 .catch((error) => console.error(error))
18 .finally(() => console.log("Done"));
19
20// Chaining promises
21fetchUser(1)
22 .then((user) => fetchUserPosts(user.id))
23 .then((posts) => processPosts(posts))
24 .then((result) => console.log(result))
25 .catch((error) => console.error(error));
Promise Combinators:
1// Promise.all - Wait for all promises
2const promises = [fetchUser(1), fetchUser(2), fetchUser(3)];
3
4Promise.all(promises)
5 .then((users) => console.log(users))
6 .catch((error) => console.error("At least one failed:", error));
7
8// Promise.allSettled - Wait for all, regardless of outcome
9Promise.allSettled(promises).then((results) => {
10 results.forEach((result) => {
11 if (result.status === "fulfilled") {
12 console.log("Success:", result.value);
13 } else {
14 console.log("Error:", result.reason);
15 }
16 });
17});
18
19// Promise.race - First to complete
20Promise.race(promises)
21 .then((winner) => console.log("First:", winner))
22 .catch((error) => console.error(error));
23
24// Promise.any - First to succeed
25Promise.any(promises)
26 .then((first) => console.log("First success:", first))
27 .catch((error) => console.error("All failed:", error));
2. Async/Await
Basic Usage:
1// Async function always returns a Promise
2async function fetchUser(id) {
3 const response = await fetch(`/api/users/${id}`);
4 const user = await response.json();
5 return user;
6}
7
8// Error handling with try/catch
9async function getUserData(id) {
10 try {
11 const user = await fetchUser(id);
12 const posts = await fetchUserPosts(user.id);
13 return { user, posts };
14 } catch (error) {
15 console.error("Error fetching data:", error);
16 throw error;
17 }
18}
19
20// Sequential vs Parallel execution
21async function sequential() {
22 const user1 = await fetchUser(1); // Wait
23 const user2 = await fetchUser(2); // Then wait
24 return [user1, user2];
25}
26
27async function parallel() {
28 const [user1, user2] = await Promise.all([fetchUser(1), fetchUser(2)]);
29 return [user1, user2];
30}
Advanced Patterns:
1// Async IIFE
2(async () => {
3 const result = await someAsyncOperation();
4 console.log(result);
5})();
6
7// Async iteration
8async function processUsers(userIds) {
9 for (const id of userIds) {
10 const user = await fetchUser(id);
11 await processUser(user);
12 }
13}
14
15// Top-level await (ES2022)
16const config = await fetch("/config.json").then((r) => r.json());
17
18// Retry logic
19async function fetchWithRetry(url, retries = 3) {
20 for (let i = 0; i < retries; i++) {
21 try {
22 return await fetch(url);
23 } catch (error) {
24 if (i === retries - 1) throw error;
25 await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));
26 }
27 }
28}
29
30// Timeout wrapper
31async function withTimeout(promise, ms) {
32 const timeout = new Promise((_, reject) =>
33 setTimeout(() => reject(new Error("Timeout")), ms),
34 );
35 return Promise.race([promise, timeout]);
36}
Functional Programming Patterns
1. Array Methods
Map, Filter, Reduce:
1const users = [
2 { id: 1, name: "John", age: 30, active: true },
3 { id: 2, name: "Jane", age: 25, active: false },
4 { id: 3, name: "Bob", age: 35, active: true },
5];
6
7// Map - Transform array
8const names = users.map((user) => user.name);
9const upperNames = users.map((user) => user.name.toUpperCase());
10
11// Filter - Select elements
12const activeUsers = users.filter((user) => user.active);
13const adults = users.filter((user) => user.age >= 18);
14
15// Reduce - Aggregate data
16const totalAge = users.reduce((sum, user) => sum + user.age, 0);
17const avgAge = totalAge / users.length;
18
19// Group by property
20const byActive = users.reduce((groups, user) => {
21 const key = user.active ? "active" : "inactive";
22 return {
23 ...groups,
24 [key]: [...(groups[key] || []), user],
25 };
26}, {});
27
28// Chaining methods
29const result = users
30 .filter((user) => user.active)
31 .map((user) => user.name)
32 .sort()
33 .join(", ");
Advanced Array Methods:
1// Find - First matching element
2const user = users.find((u) => u.id === 2);
3
4// FindIndex - Index of first match
5const index = users.findIndex((u) => u.name === "Jane");
6
7// Some - At least one matches
8const hasActive = users.some((u) => u.active);
9
10// Every - All match
11const allAdults = users.every((u) => u.age >= 18);
12
13// FlatMap - Map and flatten
14const userTags = [
15 { name: "John", tags: ["admin", "user"] },
16 { name: "Jane", tags: ["user"] },
17];
18const allTags = userTags.flatMap((u) => u.tags);
19
20// From - Create array from iterable
21const str = "hello";
22const chars = Array.from(str);
23const numbers = Array.from({ length: 5 }, (_, i) => i + 1);
24
25// Of - Create array from arguments
26const arr = Array.of(1, 2, 3);
2. Higher-Order Functions
Functions as Arguments:
1// Custom forEach
2function forEach(array, callback) {
3 for (let i = 0; i < array.length; i++) {
4 callback(array[i], i, array);
5 }
6}
7
8// Custom map
9function map(array, transform) {
10 const result = [];
11 for (const item of array) {
12 result.push(transform(item));
13 }
14 return result;
15}
16
17// Custom filter
18function filter(array, predicate) {
19 const result = [];
20 for (const item of array) {
21 if (predicate(item)) {
22 result.push(item);
23 }
24 }
25 return result;
26}
Functions Returning Functions:
1// Currying
2const multiply = (a) => (b) => a * b;
3const double = multiply(2);
4const triple = multiply(3);
5
6console.log(double(5)); // 10
7console.log(triple(5)); // 15
8
9// Partial application
10function partial(fn, ...args) {
11 return (...moreArgs) => fn(...args, ...moreArgs);
12}
13
14const add = (a, b, c) => a + b + c;
15const add5 = partial(add, 5);
16console.log(add5(3, 2)); // 10
17
18// Memoization
19function memoize(fn) {
20 const cache = new Map();
21 return (...args) => {
22 const key = JSON.stringify(args);
23 if (cache.has(key)) {
24 return cache.get(key);
25 }
26 const result = fn(...args);
27 cache.set(key, result);
28 return result;
29 };
30}
31
32const fibonacci = memoize((n) => {
33 if (n <= 1) return n;
34 return fibonacci(n - 1) + fibonacci(n - 2);
35});
3. Composition and Piping
1// Function composition
2const compose =
3 (...fns) =>
4 (x) =>
5 fns.reduceRight((acc, fn) => fn(acc), x);
6
7const pipe =
8 (...fns) =>
9 (x) =>
10 fns.reduce((acc, fn) => fn(acc), x);
11
12// Example usage
13const addOne = (x) => x + 1;
14const double = (x) => x * 2;
15const square = (x) => x * x;
16
17const composed = compose(square, double, addOne);
18console.log(composed(3)); // ((3 + 1) * 2)^2 = 64
19
20const piped = pipe(addOne, double, square);
21console.log(piped(3)); // ((3 + 1) * 2)^2 = 64
22
23// Practical example
24const processUser = pipe(
25 (user) => ({ ...user, name: user.name.trim() }),
26 (user) => ({ ...user, email: user.email.toLowerCase() }),
27 (user) => ({ ...user, age: parseInt(user.age) }),
28);
29
30const user = processUser({
31 name: " John ",
32 email: "JOHN@EXAMPLE.COM",
33 age: "30",
34});
4. Pure Functions and Immutability
1// Impure function (modifies input)
2function addItemImpure(cart, item) {
3 cart.items.push(item);
4 cart.total += item.price;
5 return cart;
6}
7
8// Pure function (no side effects)
9function addItemPure(cart, item) {
10 return {
11 ...cart,
12 items: [...cart.items, item],
13 total: cart.total + item.price,
14 };
15}
16
17// Immutable array operations
18const numbers = [1, 2, 3, 4, 5];
19
20// Add to array
21const withSix = [...numbers, 6];
22
23// Remove from array
24const withoutThree = numbers.filter((n) => n !== 3);
25
26// Update array element
27const doubled = numbers.map((n) => (n === 3 ? n * 2 : n));
28
29// Immutable object operations
30const user = { name: "John", age: 30 };
31
32// Update property
33const olderUser = { ...user, age: 31 };
34
35// Add property
36const withEmail = { ...user, email: "john@example.com" };
37
38// Remove property
39const { age, ...withoutAge } = user;
40
41// Deep cloning (simple approach)
42const deepClone = (obj) => JSON.parse(JSON.stringify(obj));
43
44// Better deep cloning
45const structuredClone = (obj) => globalThis.structuredClone(obj);
Modern Class Features
1// Class syntax
2class User {
3 // Private fields
4 #password;
5
6 // Public fields
7 id;
8 name;
9
10 // Static field
11 static count = 0;
12
13 constructor(id, name, password) {
14 this.id = id;
15 this.name = name;
16 this.#password = password;
17 User.count++;
18 }
19
20 // Public method
21 greet() {
22 return `Hello, ${this.name}`;
23 }
24
25 // Private method
26 #hashPassword(password) {
27 return `hashed_${password}`;
28 }
29
30 // Getter
31 get displayName() {
32 return this.name.toUpperCase();
33 }
34
35 // Setter
36 set password(newPassword) {
37 this.#password = this.#hashPassword(newPassword);
38 }
39
40 // Static method
41 static create(id, name, password) {
42 return new User(id, name, password);
43 }
44}
45
46// Inheritance
47class Admin extends User {
48 constructor(id, name, password, role) {
49 super(id, name, password);
50 this.role = role;
51 }
52
53 greet() {
54 return `${super.greet()}, I'm an admin`;
55 }
56}
Modules (ES6)
1// Exporting
2// math.js
3export const PI = 3.14159;
4export function add(a, b) {
5 return a + b;
6}
7export class Calculator {
8 // ...
9}
10
11// Default export
12export default function multiply(a, b) {
13 return a * b;
14}
15
16// Importing
17// app.js
18import multiply, { PI, add, Calculator } from "./math.js";
19
20// Rename imports
21import { add as sum } from "./math.js";
22
23// Import all
24import * as Math from "./math.js";
25
26// Dynamic imports
27const module = await import("./math.js");
28const { add } = await import("./math.js");
29
30// Conditional loading
31if (condition) {
32 const module = await import("./feature.js");
33 module.init();
34}
Iterators and Generators
1// Custom iterator
2const range = {
3 from: 1,
4 to: 5,
5
6 [Symbol.iterator]() {
7 return {
8 current: this.from,
9 last: this.to,
10
11 next() {
12 if (this.current <= this.last) {
13 return { done: false, value: this.current++ };
14 } else {
15 return { done: true };
16 }
17 },
18 };
19 },
20};
21
22for (const num of range) {
23 console.log(num); // 1, 2, 3, 4, 5
24}
25
26// Generator function
27function* rangeGenerator(from, to) {
28 for (let i = from; i <= to; i++) {
29 yield i;
30 }
31}
32
33for (const num of rangeGenerator(1, 5)) {
34 console.log(num);
35}
36
37// Infinite generator
38function* fibonacci() {
39 let [prev, curr] = [0, 1];
40 while (true) {
41 yield curr;
42 [prev, curr] = [curr, prev + curr];
43 }
44}
45
46// Async generator
47async function* fetchPages(url) {
48 let page = 1;
49 while (true) {
50 const response = await fetch(`${url}?page=${page}`);
51 const data = await response.json();
52 if (data.length === 0) break;
53 yield data;
54 page++;
55 }
56}
57
58for await (const page of fetchPages("/api/users")) {
59 console.log(page);
60}
Modern Operators
1// Optional chaining
2const user = { name: "John", address: { city: "NYC" } };
3const city = user?.address?.city;
4const zipCode = user?.address?.zipCode; // undefined
5
6// Function call
7const result = obj.method?.();
8
9// Array access
10const first = arr?.[0];
11
12// Nullish coalescing
13const value = null ?? "default"; // 'default'
14const value = undefined ?? "default"; // 'default'
15const value = 0 ?? "default"; // 0 (not 'default')
16const value = "" ?? "default"; // '' (not 'default')
17
18// Logical assignment
19let a = null;
20a ??= "default"; // a = 'default'
21
22let b = 5;
23b ??= 10; // b = 5 (unchanged)
24
25let obj = { count: 0 };
26obj.count ||= 1; // obj.count = 1
27obj.count &&= 2; // obj.count = 2
Performance Optimization
1// Debounce
2function debounce(fn, delay) {
3 let timeoutId;
4 return (...args) => {
5 clearTimeout(timeoutId);
6 timeoutId = setTimeout(() => fn(...args), delay);
7 };
8}
9
10const searchDebounced = debounce(search, 300);
11
12// Throttle
13function throttle(fn, limit) {
14 let inThrottle;
15 return (...args) => {
16 if (!inThrottle) {
17 fn(...args);
18 inThrottle = true;
19 setTimeout(() => (inThrottle = false), limit);
20 }
21 };
22}
23
24const scrollThrottled = throttle(handleScroll, 100);
25
26// Lazy evaluation
27function* lazyMap(iterable, transform) {
28 for (const item of iterable) {
29 yield transform(item);
30 }
31}
32
33// Use only what you need
34const numbers = [1, 2, 3, 4, 5];
35const doubled = lazyMap(numbers, (x) => x * 2);
36const first = doubled.next().value; // Only computes first value
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
Common Pitfalls
- this binding confusion: Use arrow functions or bind()
- Async/await without error handling: Always use try/catch
- Promise creation unnecessary: Don’t wrap already async functions
- Mutation of objects: Use spread operator or Object.assign()
- Forgetting await: Async functions return promises
- Blocking event loop: Avoid synchronous operations
- Memory leaks: Clean up event listeners and timers
- Not handling promise rejections: Use catch() or try/catch
Resources
- MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript
- JavaScript.info: https://javascript.info/
- You Don’t Know JS: https://github.com/getify/You-Dont-Know-JS
- Eloquent JavaScript: https://eloquentjavascript.net/
- ES6 Features: http://es6-features.org/
What Users Are Saying
Real feedback from the community
Environment Matrix
Dependencies
Framework Support
Context Window
Security & Privacy
Information
- Author
- wshobson
- Updated
- 2026-01-30
- Category
- frontend
Related Skills
Modern Javascript Patterns
Master ES6+ features including async/await, destructuring, spread operators, arrow functions, …
View Details →Byethrow
Reference the byethrow documentation to understand and use the Result type library for error …
View Details →Byethrow
Reference the byethrow documentation to understand and use the Result type library for error …
View Details →