🎯

modern-javascript-patterns

🎯Skill

from ovachiever/droid-tings

VibeIndex|
What it does

Teaches modern JavaScript techniques like async/await, destructuring, and functional patterns to write cleaner, more efficient code across web applications.

πŸ“¦

Part of

ovachiever/droid-tings(370 items)

modern-javascript-patterns

Installation

git cloneClone repository
git clone https://github.com/ovachiever/droid-tings.git
πŸ“– Extracted from docs: ovachiever/droid-tings
15Installs
20
-
AddedFeb 4, 2026

Skill Details

SKILL.md

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.

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:

```javascript

// 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:

```javascript

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:

```javascript

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:

```javascript

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:

```javascript

// 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:

```javascript

// 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

```javascript

// Basic usage

const name = 'John';

const greeting = Hello, ${name}!;

// Multi-line strings

const html = `

${title}

${content}

`;

// 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 + ${value};

}, '');

}

const name = 'John';

const age = 30;

const html = highlightName: ${name}, Age: ${age};

// Output: "Name: John, Age: 30"

```

5. Enhanced Object Literals

```javascript

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:

```javascript

// 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:

```javascript

// 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:

```javascript

// 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:

```javascript

// 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:

```javascript

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:

```javascript

// 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:

```javascript

// 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:

```javascript

// 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

```javascript

// 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

```javascript

// 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

```javascript

// 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)

```javascript

// 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

```javascript

// 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

```javascript

// 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

```javascript

// 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

  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

  • 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/