modern-javascript-patterns
About
This skill helps developers master ES6+ JavaScript features like async/await, destructuring, and functional programming patterns for writing clean, efficient code. It's ideal for refactoring legacy code, optimizing applications, and implementing modern asynchronous patterns. Use it to upgrade JavaScript syntax and adopt maintainable, performant coding practices.
Documentation
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);
}
}
2. 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];
3. 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];
4. 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 = highlight`Name: ${name}, Age: ${age}`;
// Output: "Name: <mark>John</mark>, Age: <mark>30</mark>"
5. 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));
2. 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);
2. 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);
});
3. 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'
});
4. 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 <= 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
- 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/
Quick Install
/plugin add https://github.com/camoneart/claude-code/tree/main/modern-javascript-patternsCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
sglang
MetaSGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.
llamaguard
OtherLlamaGuard is Meta's 7-8B parameter model for moderating LLM inputs and outputs across six safety categories like violence and hate speech. It offers 94-95% accuracy and can be deployed using vLLM, Hugging Face, or Amazon SageMaker. Use this skill to easily integrate content filtering and safety guardrails into your AI applications.
evaluating-llms-harness
TestingThis Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.
langchain
MetaLangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.
