Core Concepts of Function Patterns
The Central Role of Functions in JavaScript
In JavaScript, functions are not merely code blocks for executing tasks; they are first-class citizens. This means functions can:
- Be assigned to variables.
- Be passed as arguments to other functions.
- Be returned from other functions.
- Be stored in data structures.
- Be dynamically created and modified.
These characteristics make JavaScript functions the foundational building blocks for implementing various design patterns and code reuse mechanisms.
// Functions as first-class citizens
// 1. Assign to variable
const greet = function(name) {
return `Hello, ${name}!`;
};
// 2. Pass as argument
function processUserInput(callback) {
const name = prompt('Please enter your name.');
callback(name);
}
processUserInput(greet);
// 3. Return as value
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
console.log(double(5)); // 10Basic Classifications of Function Patterns
JavaScript function patterns can be categorized based on their purpose and behavior:
- Named vs. Anonymous Functions
- Function Expressions vs. Function Declarations
- Immediately Invoked Function Expressions (IIFE)
- Higher-Order Functions
- Callback Functions
- Closure Functions
- Constructor Functions
Understanding these classifications is essential for mastering advanced function patterns.
// Function Declaration vs. Function Expression
// Function Declaration
function addDeclaration(a, b) {
return a + b;
}
// Function Expression
const addExpression = function(a, b) {
return a + b;
};
// Arrow Function Expression (ES6)
const addArrow = (a, b) => a + b;Higher-Order Function Patterns
Definition and Applications of Higher-Order Functions
A Higher-Order Function (HOF) is a function that either takes a function as an argument or returns a function. This is a core concept in functional programming and a powerful abstraction tool in JavaScript.
// Higher-Order Function Example 1: Takes function as argument
function applyOperation(numbers, operation) {
return numbers.map(operation);
}
const numbers = [1, 2, 3, 4];
const doubled = applyOperation(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6, 8]
// Higher-Order Function Example 2: Returns function
function createGreeter(greeting) {
return function(name) {
console.log(`${greeting}, ${name}!`);
};
}
const sayHello = createGreeter('Hello');
sayHello('Alice'); // Hello, Alice!Common Higher-Order Function Patterns
Function Composition
Function composition combines multiple functions into a single function, where each function’s output serves as the input for the next.
// Function composition implementation
function compose(...fns) {
return function(input) {
return fns.reduceRight((acc, fn) => fn(acc), input);
};
}
// Example functions
const toUpperCase = str => str.toUpperCase();
const exclaim = str => `${str}!`;
const repeat = str => `${str} ${str}`;
// Composed function
const shout = compose(exclaim, toUpperCase);
console.log(shout('hello')); // HELLO!
const excitedShout = compose(repeat, shout);
console.log(excitedShout('hello')); // HELLO! HELLO!Currying
Currying transforms a function with multiple parameters into a series of single-parameter functions, enabling partial application.
// Currying implementation
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
}
};
}
// Original function
function sum(a, b, c) {
return a + b + c;
}
// Curried function
const curriedSum = curry(sum);
// Partial application
const addFive = curriedSum(2, 3);
console.log(addFive(4)); // 9
// Stepwise application
console.log(curriedSum(1)(2)(3)); // 6Partial Application
Partial application fixes some of a function’s parameters to create a new function, similar to currying but distinct in its approach.
// Partial application implementation
function partial(fn, ...presetArgs) {
return function(...laterArgs) {
return fn.apply(this, presetArgs.concat(laterArgs));
};
}
// Example
function greet(greeting, name) {
return `${greeting}, ${name}!`;
}
const sayHello = partial(greet, 'Hello');
console.log(sayHello('Alice')); // Hello, Alice!
const sayHiTo = partial(greet, 'Hi');
console.log(sayHiTo('Bob')); // Hi, Bob!Practical Applications of Higher-Order Functions
Data Processing Pipelines
Higher-order functions can be combined to create powerful data processing pipelines.
// Data processing pipeline example
const filter = predicate => array => array.filter(predicate);
const map = fn => array => array.map(fn);
const reduce = (reducer, initial) => array => array.reduce(reducer, initial);
// Create pipeline
const processData = pipe(
filter(x => x > 0),
map(x => x * 2),
reduce((acc, x) => acc + x, 0)
);
console.log(processData([-2, -1, 0, 1, 2, 3])); // 12Event Handling and Callbacks
Higher-order functions are invaluable in event handling and asynchronous programming.
// Event handling higher-order function
function handleEvent(element, eventType, handler) {
element.addEventListener(eventType, handler);
return function() {
element.removeEventListener(eventType, handler);
};
}
// Usage example
const button = document.getElementById('myButton');
const removeClickHandler = handleEvent(button, 'click', () => {
console.log('Button clicked!');
});
// Later, remove event listener
// removeClickHandler();



