3.3 Array Higher-Order Functions
What are Higher-Order Functions?
Higher-Order Functions are functions that accept functions as arguments or return functions. JavaScript's array higher-order functions replace imperative loops with functional style, making code more concise and readable.
map — Transform
Transforms each element and returns a new array. Original array is unchanged.
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] (original unchanged)
// Transform object arrays
const users = [
{ id: 1, name: "Alice", age: 25 },
{ id: 2, name: "Bob", age: 30 },
];
const names = users.map(user => user.name);
console.log(names); // ["Alice", "Bob"]
// Transform API response
const apiUsers = [
{ user_id: 1, display_name: "alice", email_address: "alice@example.com" },
];
const normalized = apiUsers.map(user => ({
id: user.user_id,
name: user.display_name,
email: user.email_address,
}));
filter — Conditional Filtering
Returns a new array with only elements matching the condition.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]
const products = [
{ name: "Laptop", price: 1200, inStock: true },
{ name: "Mouse", price: 35, inStock: false },
{ name: "Keyboard", price: 85, inStock: true },
];
const available = products.filter(p => p.inStock);
const affordable = products.filter(p => p.price <= 100);
const bestDeals = products.filter(p => p.inStock && p.price <= 100);
// Remove falsy values
const mixed = ["a", null, "b", undefined, "", "c", false];
const truthy = mixed.filter(Boolean);
console.log(truthy); // ["a", "b", "c"]
reduce — Accumulator
Reduces an array to a single value.
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 15
// Maximum value
const max = numbers.reduce((max, cur) => cur > max ? cur : max, -Infinity);
console.log(max); // 5
// Grouping into object
const words = ["apple", "banana", "avocado", "blueberry", "cherry"];
const grouped = words.reduce((acc, word) => {
const letter = word[0];
acc[letter] ??= [];
acc[letter].push(word);
return acc;
}, {});
// { a: ["apple", "avocado"], b: ["banana", "blueberry"], c: ["cherry"] }
// Sum from object array
const orders = [
{ product: "Laptop", quantity: 1, price: 1200 },
{ product: "Mouse", quantity: 2, price: 35 },
];
const total = orders.reduce((sum, order) => sum + (order.quantity * order.price), 0);
console.log(total); // 1270
find and findIndex
Return the first element (or index) matching the condition.
const users = [
{ id: 1, name: "Alice", role: "user" },
{ id: 2, name: "Bob", role: "admin" },
];
const admin = users.find(u => u.role === "admin");
console.log(admin); // { id: 2, name: "Bob", role: "admin" }
const adminIndex = users.findIndex(u => u.role === "admin");
console.log(adminIndex); // 1
// findLast / findLastIndex (ES2023): search from the end
const numbers = [1, 3, 5, 2, 4, 6, 3, 7];
const lastOdd = numbers.findLast(n => n % 2 !== 0);
console.log(lastOdd); // 7
some and every
Returns boolean from condition checks.
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.some(n => n > 4)); // true
console.log(numbers.some(n => n > 10)); // false
console.log(numbers.every(n => n > 0)); // true
console.log(numbers.every(n => n > 2)); // false
// Validation
const formFields = [
{ name: "name", value: "Alice", required: true },
{ name: "email", value: "alice@test.com", required: true },
{ name: "address", value: "", required: false },
];
const isValid = formFields
.filter(f => f.required)
.every(f => f.value.trim() !== "");
console.log(isValid); // true
flat and flatMap
Flattens nested arrays.
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]] (1 level)
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]
console.log(nested.flat(Infinity)); // flatten all
// flatMap: map then flat(1)
const sentences = ["Hello World", "JavaScript is fun"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words); // ["Hello", "World", "JavaScript", "is", "fun"]
// Conditional element adding
const items = [1, 2, 3, 4, 5];
const processed = items.flatMap(n => n % 2 === 0 ? [n, n * 2] : [n]);
console.log(processed); // [1, 2, 4, 3, 4, 8, 5]
Method Chaining
const transactions = [
{ type: "income", amount: 500 },
{ type: "expense", amount: 45 },
{ type: "income", amount: 200 },
{ type: "expense", amount: 120 },
];
const totalExpense = transactions
.filter(t => t.type === "expense")
.map(t => t.amount)
.reduce((sum, amount) => sum + amount, 0);
console.log(totalExpense); // 165
Pro Tips
Implementing map and filter with reduce
const myMap = (arr, fn) => arr.reduce((acc, item) => [...acc, fn(item)], []);
const myFilter = (arr, fn) => arr.reduce((acc, item) => fn(item) ? [...acc, item] : acc, []);
// Single-pass filter + map (more efficient)
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = numbers.reduce((acc, n) => {
if (n % 2 === 0) acc.push(n * 2);
return acc;
}, []);
console.log(result); // [4, 8, 12, 16, 20]
Latest Array Methods (ES2023+)
const arr = [1, 2, 3, 4, 5];
// toSorted: immutable version of sort
const sorted = arr.toSorted((a, b) => b - a);
console.log(sorted); // [5, 4, 3, 2, 1]
console.log(arr); // [1, 2, 3, 4, 5] (original preserved)
// toReversed: immutable version of reverse
const reversed = arr.toReversed();
console.log(reversed); // [5, 4, 3, 2, 1]
// with: replace element at index (immutable)
const updated = arr.with(2, 30);
console.log(updated); // [1, 2, 30, 4, 5]