Modern Javascript Patterns

Write modern, clean JavaScript with ES6+ patterns and best practices

✨ The solution you've been looking for

Verified
Tested and verified by our team
25450 Stars

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.

javascript es6 modern-js async-await functional-programming destructuring arrow-functions promises
Repository

See It In Action

Interactive preview & real-world examples

Live Demo
Skill Demo Animation

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

1

Install

claude-code skill install modern-javascript-patterns

claude-code skill install modern-javascript-patterns
2

Config

3

First Trigger

@modern-javascript-patterns help

Commands

CommandDescriptionRequired Args
@modern-javascript-patterns legacy-code-modernizationTransform outdated JavaScript code using modern ES6+ syntax and patternsNone
@modern-javascript-patterns functional-programming-implementationApply functional programming concepts for data transformation and processingNone
@modern-javascript-patterns asynchronous-operation-optimizationImplement efficient async patterns for API calls and data fetchingNone

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

  1. Use const by default: Only use let when reassignment is needed
  2. Prefer arrow functions: Especially for callbacks
  3. Use template literals: Instead of string concatenation
  4. Destructure objects and arrays: For cleaner code
  5. Use async/await: Instead of Promise chains
  6. Avoid mutating data: Use spread operator and array methods
  7. Use optional chaining: Prevent “Cannot read property of undefined”
  8. Use nullish coalescing: For default values
  9. Prefer array methods: Over traditional loops
  10. Use modules: For better code organization
  11. Write pure functions: Easier to test and reason about
  12. Use meaningful variable names: Self-documenting code
  13. Keep functions small: Single responsibility principle
  14. Handle errors properly: Use try/catch with async/await
  15. Use strict mode: 'use strict' for better error catching

Common Pitfalls

  1. this binding confusion: Use arrow functions or bind()
  2. Async/await without error handling: Always use try/catch
  3. Promise creation unnecessary: Don’t wrap already async functions
  4. Mutation of objects: Use spread operator or Object.assign()
  5. Forgetting await: Async functions return promises
  6. Blocking event loop: Avoid synchronous operations
  7. Memory leaks: Clean up event listeners and timers
  8. Not handling promise rejections: Use catch() or try/catch

Resources

What Users Are Saying

Real feedback from the community

Environment Matrix

Dependencies

Modern JavaScript runtime (ES6+ support)
Node.js 14+ or modern browser

Framework Support

React ✓ (recommended) Vue.js ✓ Angular ✓ Node.js ✓ Vanilla JavaScript ✓

Context Window

Token Usage ~3K-8K tokens for comprehensive pattern examples and refactoring tasks

Security & Privacy

Information

Author
wshobson
Updated
2026-01-30
Category
frontend