Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply modern ES2020+ JavaScript patterns: modules, async/await, optional chaining, and functional idioms.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/advanced-patterns.md
1# Advanced Modern JavaScript Patterns23Advanced patterns covering functional programming, modern class features, ES6 modules, iterators, generators, modern operators, and performance optimization.45## Functional Programming Patterns67### 1. Array Methods89**Map, Filter, Reduce:**1011```javascript12const users = [13{ id: 1, name: "John", age: 30, active: true },14{ id: 2, name: "Jane", age: 25, active: false },15{ id: 3, name: "Bob", age: 35, active: true },16];1718// Map - Transform array19const names = users.map((user) => user.name);20const upperNames = users.map((user) => user.name.toUpperCase());2122// Filter - Select elements23const activeUsers = users.filter((user) => user.active);24const adults = users.filter((user) => user.age >= 18);2526// Reduce - Aggregate data27const totalAge = users.reduce((sum, user) => sum + user.age, 0);28const avgAge = totalAge / users.length;2930// Group by property31const byActive = users.reduce((groups, user) => {32const key = user.active ? "active" : "inactive";33return {34...groups,35[key]: [...(groups[key] || []), user],36};37}, {});3839// Chaining methods40const result = users41.filter((user) => user.active)42.map((user) => user.name)43.sort()44.join(", ");45```4647**Advanced Array Methods:**4849```javascript50// Find - First matching element51const user = users.find((u) => u.id === 2);5253// FindIndex - Index of first match54const index = users.findIndex((u) => u.name === "Jane");5556// Some - At least one matches57const hasActive = users.some((u) => u.active);5859// Every - All match60const allAdults = users.every((u) => u.age >= 18);6162// FlatMap - Map and flatten63const userTags = [64{ name: "John", tags: ["admin", "user"] },65{ name: "Jane", tags: ["user"] },66];67const allTags = userTags.flatMap((u) => u.tags);6869// From - Create array from iterable70const str = "hello";71const chars = Array.from(str);72const numbers = Array.from({ length: 5 }, (_, i) => i + 1);7374// Of - Create array from arguments75const arr = Array.of(1, 2, 3);76```7778### 2. Higher-Order Functions7980**Functions as Arguments:**8182```javascript83// Custom forEach84function forEach(array, callback) {85for (let i = 0; i < array.length; i++) {86callback(array[i], i, array);87}88}8990// Custom map91function map(array, transform) {92const result = [];93for (const item of array) {94result.push(transform(item));95}96return result;97}9899// Custom filter100function filter(array, predicate) {101const result = [];102for (const item of array) {103if (predicate(item)) {104result.push(item);105}106}107return result;108}109```110111**Functions Returning Functions:**112113```javascript114// Currying115const multiply = (a) => (b) => a * b;116const double = multiply(2);117const triple = multiply(3);118119console.log(double(5)); // 10120console.log(triple(5)); // 15121122// Partial application123function partial(fn, ...args) {124return (...moreArgs) => fn(...args, ...moreArgs);125}126127const add = (a, b, c) => a + b + c;128const add5 = partial(add, 5);129console.log(add5(3, 2)); // 10130131// Memoization132function memoize(fn) {133const cache = new Map();134return (...args) => {135const key = JSON.stringify(args);136if (cache.has(key)) {137return cache.get(key);138}139const result = fn(...args);140cache.set(key, result);141return result;142};143}144145const fibonacci = memoize((n) => {146if (n <= 1) return n;147return fibonacci(n - 1) + fibonacci(n - 2);148});149```150151### 3. Composition and Piping152153```javascript154// Function composition155const compose =156(...fns) =>157(x) =>158fns.reduceRight((acc, fn) => fn(acc), x);159160const pipe =161(...fns) =>162(x) =>163fns.reduce((acc, fn) => fn(acc), x);164165// Example usage166const addOne = (x) => x + 1;167const double = (x) => x * 2;168const square = (x) => x * x;169170const composed = compose(square, double, addOne);171console.log(composed(3)); // ((3 + 1) * 2)^2 = 64172173const piped = pipe(addOne, double, square);174console.log(piped(3)); // ((3 + 1) * 2)^2 = 64175176// Practical example177const processUser = pipe(178(user) => ({ ...user, name: user.name.trim() }),179(user) => ({ ...user, email: user.email.toLowerCase() }),180(user) => ({ ...user, age: parseInt(user.age) }),181);182183const user = processUser({184name: " John ",185email: "[email protected]",186age: "30",187});188```189190### 4. Pure Functions and Immutability191192```javascript193// Impure function (modifies input)194function addItemImpure(cart, item) {195cart.items.push(item);196cart.total += item.price;197return cart;198}199200// Pure function (no side effects)201function addItemPure(cart, item) {202return {203...cart,204items: [...cart.items, item],205total: cart.total + item.price,206};207}208209// Immutable array operations210const numbers = [1, 2, 3, 4, 5];211212// Add to array213const withSix = [...numbers, 6];214215// Remove from array216const withoutThree = numbers.filter((n) => n !== 3);217218// Update array element219const doubled = numbers.map((n) => (n === 3 ? n * 2 : n));220221// Immutable object operations222const user = { name: "John", age: 30 };223224// Update property225const olderUser = { ...user, age: 31 };226227// Add property228const withEmail = { ...user, email: "[email protected]" };229230// Remove property231const { age, ...withoutAge } = user;232233// Deep cloning (simple approach)234const deepClone = (obj) => JSON.parse(JSON.stringify(obj));235236// Better deep cloning237const structuredClone = (obj) => globalThis.structuredClone(obj);238```239240## Modern Class Features241242```javascript243// Class syntax244class User {245// Private fields246#password;247248// Public fields249id;250name;251252// Static field253static count = 0;254255constructor(id, name, password) {256this.id = id;257this.name = name;258this.#password = password;259User.count++;260}261262// Public method263greet() {264return `Hello, ${this.name}`;265}266267// Private method268#hashPassword(password) {269return `hashed_${password}`;270}271272// Getter273get displayName() {274return this.name.toUpperCase();275}276277// Setter278set password(newPassword) {279this.#password = this.#hashPassword(newPassword);280}281282// Static method283static create(id, name, password) {284return new User(id, name, password);285}286}287288// Inheritance289class Admin extends User {290constructor(id, name, password, role) {291super(id, name, password);292this.role = role;293}294295greet() {296return `${super.greet()}, I'm an admin`;297}298}299```300301## Modules (ES6)302303```javascript304// Exporting305// math.js306export const PI = 3.14159;307export function add(a, b) {308return a + b;309}310export class Calculator {311// ...312}313314// Default export315export default function multiply(a, b) {316return a * b;317}318319// Importing320// app.js321import multiply, { PI, add, Calculator } from "./math.js";322323// Rename imports324import { add as sum } from "./math.js";325326// Import all327import * as Math from "./math.js";328329// Dynamic imports330const module = await import("./math.js");331const { add } = await import("./math.js");332333// Conditional loading334if (condition) {335const module = await import("./feature.js");336module.init();337}338```339340## Iterators and Generators341342```javascript343// Custom iterator344const range = {345from: 1,346to: 5,347348[Symbol.iterator]() {349return {350current: this.from,351last: this.to,352353next() {354if (this.current <= this.last) {355return { done: false, value: this.current++ };356} else {357return { done: true };358}359},360};361},362};363364for (const num of range) {365console.log(num); // 1, 2, 3, 4, 5366}367368// Generator function369function* rangeGenerator(from, to) {370for (let i = from; i <= to; i++) {371yield i;372}373}374375for (const num of rangeGenerator(1, 5)) {376console.log(num);377}378379// Infinite generator380function* fibonacci() {381let [prev, curr] = [0, 1];382while (true) {383yield curr;384[prev, curr] = [curr, prev + curr];385}386}387388// Async generator389async function* fetchPages(url) {390let page = 1;391while (true) {392const response = await fetch(`${url}?page=${page}`);393const data = await response.json();394if (data.length === 0) break;395yield data;396page++;397}398}399400for await (const page of fetchPages("/api/users")) {401console.log(page);402}403```404405## Modern Operators406407```javascript408// Optional chaining409const user = { name: "John", address: { city: "NYC" } };410const city = user?.address?.city;411const zipCode = user?.address?.zipCode; // undefined412413// Function call414const result = obj.method?.();415416// Array access417const first = arr?.[0];418419// Nullish coalescing420const value = null ?? "default"; // 'default'421const value = undefined ?? "default"; // 'default'422const value = 0 ?? "default"; // 0 (not 'default')423const value = "" ?? "default"; // '' (not 'default')424425// Logical assignment426let a = null;427a ??= "default"; // a = 'default'428429let b = 5;430b ??= 10; // b = 5 (unchanged)431432let obj = { count: 0 };433obj.count ||= 1; // obj.count = 1434obj.count &&= 2; // obj.count = 2435```436437## Performance Optimization438439```javascript440// Debounce441function debounce(fn, delay) {442let timeoutId;443return (...args) => {444clearTimeout(timeoutId);445timeoutId = setTimeout(() => fn(...args), delay);446};447}448449const searchDebounced = debounce(search, 300);450451// Throttle452function throttle(fn, limit) {453let inThrottle;454return (...args) => {455if (!inThrottle) {456fn(...args);457inThrottle = true;458setTimeout(() => (inThrottle = false), limit);459}460};461}462463const scrollThrottled = throttle(handleScroll, 100);464465// Lazy evaluation466function* lazyMap(iterable, transform) {467for (const item of iterable) {468yield transform(item);469}470}471472// Use only what you need473const numbers = [1, 2, 3, 4, 5];474const doubled = lazyMap(numbers, (x) => x * 2);475const first = doubled.next().value; // Only computes first value476```477478## Common Pitfalls4794801. **this binding confusion**: Use arrow functions or bind()4812. **Async/await without error handling**: Always use try/catch4823. **Promise creation unnecessary**: Don't wrap already async functions4834. **Mutation of objects**: Use spread operator or Object.assign()4845. **Forgetting await**: Async functions return promises4856. **Blocking event loop**: Avoid synchronous operations4867. **Memory leaks**: Clean up event listeners and timers4878. **Not handling promise rejections**: Use catch() or try/catch488