modern-javascript-patterns

Modern JavaScript Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "modern-javascript-patterns" with this command: npx skills add hermeticormus/libreuiux-claude-code/hermeticormus-libreuiux-claude-code-modern-javascript-patterns

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:

// Traditional function function add(a, b) { return a + b; }

// Arrow function const add = (a, b) => a + b;

// Single parameter (parentheses optional) const double = x => x * 2;

// No parameters const getRandom = () => Math.random();

// Multiple statements (need curly braces) const processUser = user => { const normalized = user.name.toLowerCase(); return { ...user, name: normalized }; };

// Returning objects (wrap in parentheses) const createUser = (name, age) => ({ name, age });

Lexical 'this' Binding:

class Counter { constructor() { this.count = 0; }

// Arrow function preserves 'this' context increment = () => { this.count++; };

// Traditional function loses 'this' in callbacks incrementTraditional() { setTimeout(function() { this.count++; // 'this' is undefined }, 1000); }

// Arrow function maintains 'this' incrementArrow() { setTimeout(() => { this.count++; // 'this' refers to Counter instance }, 1000); } }

  1. Destructuring

Object Destructuring:

const user = { id: 1, name: 'John Doe', email: 'john@example.com', address: { city: 'New York', country: 'USA' } };

// Basic destructuring const { name, email } = user;

// Rename variables const { name: userName, email: userEmail } = user;

// Default values const { age = 25 } = user;

// Nested destructuring const { address: { city, country } } = user;

// Rest operator const { id, ...userWithoutId } = user;

// Function parameters function greet({ name, age = 18 }) { console.log(Hello ${name}, you are ${age}); } greet(user);

Array Destructuring:

const numbers = [1, 2, 3, 4, 5];

// Basic destructuring const [first, second] = numbers;

// Skip elements const [, , third] = numbers;

// Rest operator const [head, ...tail] = numbers;

// Swapping variables let a = 1, b = 2; [a, b] = [b, a];

// Function return values function getCoordinates() { return [10, 20]; } const [x, y] = getCoordinates();

// Default values const [one, two, three = 0] = [1, 2];

  1. Spread and Rest Operators

Spread Operator:

// Array spreading const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const combined = [...arr1, ...arr2];

// Object spreading const defaults = { theme: 'dark', lang: 'en' }; const userPrefs = { theme: 'light' }; const settings = { ...defaults, ...userPrefs };

// Function arguments const numbers = [1, 2, 3]; Math.max(...numbers);

// Copying arrays/objects (shallow copy) const copy = [...arr1]; const objCopy = { ...user };

// Adding items immutably const newArr = [...arr1, 4, 5]; const newObj = { ...user, age: 30 };

Rest Parameters:

// Collect function arguments function sum(...numbers) { return numbers.reduce((total, num) => total + num, 0); } sum(1, 2, 3, 4, 5);

// With regular parameters function greet(greeting, ...names) { return ${greeting} ${names.join(', ')}; } greet('Hello', 'John', 'Jane', 'Bob');

// Object rest const { id, ...userData } = user;

// Array rest const [first, ...rest] = [1, 2, 3, 4, 5];

  1. Template Literals

// Basic usage const name = 'John'; const greeting = Hello, ${name}!;

// Multi-line strings const html = <div> <h1>${title}</h1> <p>${content}</p> </div>;

// Expression evaluation const price = 19.99; const total = Total: $${(price * 1.2).toFixed(2)};

// Tagged template literals 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 = highlightName: ${name}, Age: ${age}; // Output: "Name: <mark>John</mark>, Age: <mark>30</mark>"

  1. Enhanced Object Literals

const name = 'John'; const age = 30;

// Shorthand property names const user = { name, age };

// Shorthand method names const calculator = { add(a, b) { return a + b; }, subtract(a, b) { return a - b; } };

// Computed property names const field = 'email'; const user = { name: 'John', [field]: 'john@example.com', get${field.charAt(0).toUpperCase()}${field.slice(1)} { return this[field]; } };

// Dynamic property creation const createUser = (name, ...props) => { return props.reduce((user, [key, value]) => ({ ...user, [key]: value }), { name }); };

const user = createUser('John', ['age', 30], ['email', 'john@example.com']);

Asynchronous Patterns

  1. Promises

Creating and Using Promises:

// Creating a promise const fetchUser = (id) => { return new Promise((resolve, reject) => { setTimeout(() => { if (id > 0) { resolve({ id, name: 'John' }); } else { reject(new Error('Invalid ID')); } }, 1000); }); };

// Using promises fetchUser(1) .then(user => console.log(user)) .catch(error => console.error(error)) .finally(() => console.log('Done'));

// Chaining promises fetchUser(1) .then(user => fetchUserPosts(user.id)) .then(posts => processPosts(posts)) .then(result => console.log(result)) .catch(error => console.error(error));

Promise Combinators:

// Promise.all - Wait for all promises 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 - Wait for all, regardless of outcome 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 - First to complete Promise.race(promises) .then(winner => console.log('First:', winner)) .catch(error => console.error(error));

// Promise.any - First to succeed Promise.any(promises) .then(first => console.log('First success:', first)) .catch(error => console.error('All failed:', error));

  1. Async/Await

Basic Usage:

// Async function always returns a Promise async function fetchUser(id) { const response = await fetch(/api/users/${id}); const user = await response.json(); return user; }

// Error handling with try/catch 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; } }

// Sequential vs Parallel execution async function sequential() { const user1 = await fetchUser(1); // Wait const user2 = await fetchUser(2); // Then wait return [user1, user2]; }

async function parallel() { const [user1, user2] = await Promise.all([ fetchUser(1), fetchUser(2) ]); return [user1, user2]; }

Advanced Patterns:

// Async IIFE (async () => { const result = await someAsyncOperation(); console.log(result); })();

// Async iteration async function processUsers(userIds) { for (const id of userIds) { const user = await fetchUser(id); await processUser(user); } }

// Top-level await (ES2022) const config = await fetch('/config.json').then(r => r.json());

// Retry logic 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 => setTimeout(resolve, 1000 * (i + 1))); } } }

// Timeout wrapper async function withTimeout(promise, ms) { const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms) ); return Promise.race([promise, timeout]); }

Functional Programming Patterns

  1. Array Methods

Map, Filter, Reduce:

const users = [ { id: 1, name: 'John', age: 30, active: true }, { id: 2, name: 'Jane', age: 25, active: false }, { id: 3, name: 'Bob', age: 35, active: true } ];

// Map - Transform array const names = users.map(user => user.name); const upperNames = users.map(user => user.name.toUpperCase());

// Filter - Select elements const activeUsers = users.filter(user => user.active); const adults = users.filter(user => user.age >= 18);

// Reduce - Aggregate data const totalAge = users.reduce((sum, user) => sum + user.age, 0); const avgAge = totalAge / users.length;

// Group by property const byActive = users.reduce((groups, user) => { const key = user.active ? 'active' : 'inactive'; return { ...groups, [key]: [...(groups[key] || []), user] }; }, {});

// Chaining methods const result = users .filter(user => user.active) .map(user => user.name) .sort() .join(', ');

Advanced Array Methods:

// Find - First matching element const user = users.find(u => u.id === 2);

// FindIndex - Index of first match const index = users.findIndex(u => u.name === 'Jane');

// Some - At least one matches const hasActive = users.some(u => u.active);

// Every - All match const allAdults = users.every(u => u.age >= 18);

// FlatMap - Map and flatten const userTags = [ { name: 'John', tags: ['admin', 'user'] }, { name: 'Jane', tags: ['user'] } ]; const allTags = userTags.flatMap(u => u.tags);

// From - Create array from iterable const str = 'hello'; const chars = Array.from(str); const numbers = Array.from({ length: 5 }, (_, i) => i + 1);

// Of - Create array from arguments const arr = Array.of(1, 2, 3);

  1. Higher-Order Functions

Functions as Arguments:

// Custom forEach function forEach(array, callback) { for (let i = 0; i < array.length; i++) { callback(array[i], i, array); } }

// Custom map function map(array, transform) { const result = []; for (const item of array) { result.push(transform(item)); } return result; }

// Custom filter function filter(array, predicate) { const result = []; for (const item of array) { if (predicate(item)) { result.push(item); } } return result; }

Functions Returning Functions:

// Currying const multiply = a => b => a * b; const double = multiply(2); const triple = multiply(3);

console.log(double(5)); // 10 console.log(triple(5)); // 15

// Partial application function partial(fn, ...args) { return (...moreArgs) => fn(...args, ...moreArgs); }

const add = (a, b, c) => a + b + c; const add5 = partial(add, 5); console.log(add5(3, 2)); // 10

// Memoization function 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; }; }

const fibonacci = memoize((n) => { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); });

  1. Composition and Piping

// Function composition const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);

const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);

// Example usage const addOne = x => x + 1; const double = x => x * 2; const square = x => x * x;

const composed = compose(square, double, addOne); console.log(composed(3)); // ((3 + 1) * 2)^2 = 64

const piped = pipe(addOne, double, square); console.log(piped(3)); // ((3 + 1) * 2)^2 = 64

// Practical example const processUser = pipe( user => ({ ...user, name: user.name.trim() }), user => ({ ...user, email: user.email.toLowerCase() }), user => ({ ...user, age: parseInt(user.age) }) );

const user = processUser({ name: ' John ', email: 'JOHN@EXAMPLE.COM', age: '30' });

  1. Pure Functions and Immutability

// Impure function (modifies input) function addItemImpure(cart, item) { cart.items.push(item); cart.total += item.price; return cart; }

// Pure function (no side effects) function addItemPure(cart, item) { return { ...cart, items: [...cart.items, item], total: cart.total + item.price }; }

// Immutable array operations const numbers = [1, 2, 3, 4, 5];

// Add to array const withSix = [...numbers, 6];

// Remove from array const withoutThree = numbers.filter(n => n !== 3);

// Update array element const doubled = numbers.map(n => n === 3 ? n * 2 : n);

// Immutable object operations const user = { name: 'John', age: 30 };

// Update property const olderUser = { ...user, age: 31 };

// Add property const withEmail = { ...user, email: 'john@example.com' };

// Remove property const { age, ...withoutAge } = user;

// Deep cloning (simple approach) const deepClone = obj => JSON.parse(JSON.stringify(obj));

// Better deep cloning const structuredClone = obj => globalThis.structuredClone(obj);

Modern Class Features

// Class syntax class User { // Private fields #password;

// Public fields id; name;

// Static field static count = 0;

constructor(id, name, password) { this.id = id; this.name = name; this.#password = password; User.count++; }

// Public method greet() { return Hello, ${this.name}; }

// Private method #hashPassword(password) { return hashed_${password}; }

// Getter get displayName() { return this.name.toUpperCase(); }

// Setter set password(newPassword) { this.#password = this.#hashPassword(newPassword); }

// Static method static create(id, name, password) { return new User(id, name, password); } }

// Inheritance class Admin extends User { constructor(id, name, password, role) { super(id, name, password); this.role = role; }

greet() { return ${super.greet()}, I'm an admin; } }

Modules (ES6)

// Exporting // math.js export const PI = 3.14159; export function add(a, b) { return a + b; } export class Calculator { // ... }

// Default export export default function multiply(a, b) { return a * b; }

// Importing // app.js import multiply, { PI, add, Calculator } from './math.js';

// Rename imports import { add as sum } from './math.js';

// Import all import * as Math from './math.js';

// Dynamic imports const module = await import('./math.js'); const { add } = await import('./math.js');

// Conditional loading if (condition) { const module = await import('./feature.js'); module.init(); }

Iterators and Generators

// Custom iterator const range = { from: 1, to: 5,

Symbol.iterator { return { current: this.from, last: this.to,

  next() {
    if (this.current &#x3C;= this.last) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  }
};

} };

for (const num of range) { console.log(num); // 1, 2, 3, 4, 5 }

// Generator function function* rangeGenerator(from, to) { for (let i = from; i <= to; i++) { yield i; } }

for (const num of rangeGenerator(1, 5)) { console.log(num); }

// Infinite generator function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { yield curr; [prev, curr] = [curr, prev + curr]; } }

// Async generator async function* fetchPages(url) { let page = 1; while (true) { const response = await fetch(${url}?page=${page}); const data = await response.json(); if (data.length === 0) break; yield data; page++; } }

for await (const page of fetchPages('/api/users')) { console.log(page); }

Modern Operators

// Optional chaining const user = { name: 'John', address: { city: 'NYC' } }; const city = user?.address?.city; const zipCode = user?.address?.zipCode; // undefined

// Function call const result = obj.method?.();

// Array access const first = arr?.[0];

// Nullish coalescing const value = null ?? 'default'; // 'default' const value = undefined ?? 'default'; // 'default' const value = 0 ?? 'default'; // 0 (not 'default') const value = '' ?? 'default'; // '' (not 'default')

// Logical assignment let a = null; a ??= 'default'; // a = 'default'

let b = 5; b ??= 10; // b = 5 (unchanged)

let obj = { count: 0 }; obj.count ||= 1; // obj.count = 1 obj.count &&= 2; // obj.count = 2

Performance Optimization

// Debounce function debounce(fn, delay) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn(...args), delay); }; }

const searchDebounced = debounce(search, 300);

// Throttle function throttle(fn, limit) { let inThrottle; return (...args) => { if (!inThrottle) { fn(...args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }

const scrollThrottled = throttle(handleScroll, 100);

// Lazy evaluation function* lazyMap(iterable, transform) { for (const item of iterable) { yield transform(item); } }

// Use only what you need const numbers = [1, 2, 3, 4, 5]; const doubled = lazyMap(numbers, x => x * 2); const 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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

premium-saas-design

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

design-principles

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

debugging-strategies

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

prompt-engineering-ui

No summary provided by upstream source.

Repository SourceNeeds Review