Lesson 10: Array Methods - map, filter, reduce
What You'll Learn
- Higher-order array methods
map()- transform each elementfilter()- select elementsreduce()- combine elementsfind()andfindIndex()some()andevery()- Method chaining
Why This Matters
Array methods are powerful tools that let you process data without writing explicit loops. They make your code shorter, clearer, and more functional. These methods are used everywhere in modern JavaScript development.
---
Part 1: What are Higher-Order Functions?
A higher-order function is a function that:
- Takes another function as an argument, OR
- Returns a function
Array methods like map, filter, and reduce take functions as arguments.
lesson-10/array-methods.js
---
Part 2: The map() Method
map() creates a new array by transforming each element.
Basic Example
const numbers = [1, 2, 3, 4, 5];
// Transform each number by doubling it
const doubled = numbers.map((num) => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] - original unchanged
How map() Works
// What map does (simplified):
function map(array, transformFunction) {
const result = [];
for (const item of array) {
result.push(transformFunction(item));
}
return result;
}
The Callback Function
const numbers = [1, 2, 3];
// Arrow function (concise)
const doubled = numbers.map(num => num * 2);
// Full arrow function
const doubled2 = numbers.map((num) => {
return num * 2;
});
// Traditional function
const doubled3 = numbers.map(function(num) {
return num * 2;
});
map() with Index and Array
const numbers = [10, 20, 30];
// Callback gets: (element, index, wholeArray)
const result = numbers.map((num, index, array) => {
console.log(`Index ${index}: ${num} (Array length: ${array.length})`);
return num * index;
});
console.log(result); // [0, 20, 60]
Practical Examples
// Convert strings to uppercase
const names = ["alice", "bob", "charlie"];
const uppercased = names.map(name => name.toUpperCase());
console.log(uppercased); // ["ALICE", "BOB", "CHARLIE"]
// Extract property from objects
const products[] = [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 25 },
{ name: "Keyboard", price: 75 }
];
const prices = products.map(product => product.price);
console.log(prices); // [999, 25, 75]
// Add tax to prices
const pricesWithTax = prices.map(price => price * 1.1);
console.log(pricesWithTax); // [1098.9, 27.5, 82.5]
---
Part 3: The filter() Method
filter() creates a new array with only elements that pass a test.
Basic Example
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Keep only even numbers
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6, 8, 10]
How filter() Works
// What filter does (simplified):
function filter(array, testFunction) {
const result = [];
for (const item of array) {
if (testFunction(item)) { // If test passes
result.push(item); // Include in result
}
}
return result;
}
Practical Examples
// Filter numbers greater than 5
const numbers = [3, 8, 1, 9, 2, 7];
const bigNumbers = numbers.filter(num => num > 5);
console.log(bigNumbers); // [8, 9, 7]
// Filter strings by length
const words = ["cat", "elephant", "dog", "butterfly"];
const longWords = words.filter(word => word.length > 5);
console.log(longWords); // ["elephant", "butterfly"]
// Filter objects by condition
const users[] = [
{ name: "Alice", age: 30, isActive: true },
{ name: "Bob", age: 17, isActive: false },
{ name: "Charlie", age: 25, isActive: true }
];
// Get only active adult users
const activeAdults[] = users.filter(user =>
user.age >= 18 && user.isActive
);
console.log(activeAdults);
// [{ name: "Alice", age: 30, isActive: true },
// { name: "Charlie", age: 25, isActive: true }]
---
Part 4: The reduce() Method
reduce() reduces an array to a single value by combining elements.
Basic Example - Sum
const numbers = [1, 2, 3, 4, 5];
// Add all numbers together
const sum = numbers.reduce((accumulator, current) => {
return accumulator + current;
}, 0); // 0 is the initial value
console.log(sum); // 15
Understanding reduce()
// How reduce works step-by-step:
const numbers = [1, 2, 3, 4, 5];
// Initial value: 0
// Step 1: accumulator=0, current=1 → return 0+1 = 1
// Step 2: accumulator=1, current=2 → return 1+2 = 3
// Step 3: accumulator=3, current=3 → return 3+3 = 6
// Step 4: accumulator=6, current=4 → return 6+4 = 10
// Step 5: accumulator=10, current=5 → return 10+5 = 15
// Result: 15
Reduce Syntax
array.reduce((accumulator, currentValue, index, array) => {
// Return the new accumulator value
}, initialValue);
- accumulator: The result so far
- currentValue: Current element being processed
- initialValue: Starting value for accumulator
Practical Examples
// Find maximum number
const numbers = [45, 23, 78, 12, 99, 34];
const max = numbers.reduce((max, current) => {
return current > max ? current : max;
}, numbers[0]);
console.log(max); // 99
// Count occurrences
const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {} as Record);
console.log(count); // { apple: 3, banana: 2, orange: 1 }
// Calculate total price
const cart[] = [
{ name: "Laptop", price: 999, quantity: 1 },
{ name: "Mouse", price: 25, quantity: 2 },
{ name: "Keyboard", price: 75, quantity: 1 }
];
const total = cart.reduce((sum, item) => {
return sum + (item.price * item.quantity);
}, 0);
console.log(`Total: $${total}`); // Total: $1124
// Flatten array of arrays
const nested[] = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, current) => {
return acc.concat(current);
}, []);
console.log(flat); // [1, 2, 3, 4, 5, 6]
---
Part 5: The find() Method
find() returns the first element that passes a test.
const numbers = [5, 12, 8, 130, 44];
// Find first number > 10
const found | undefined = numbers.find(num => num > 10);
console.log(found); // 12
// Find first number > 200
const notFound = numbers.find(num => num > 200);
console.log(notFound); // undefined
// Find user by ID
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
];
const user = users.find(user => user.id === 2);
console.log(user); // { id: 2, name: "Bob" }
---
Part 6: The findIndex() Method
findIndex() returns the index of the first element that passes a test.
const numbers = [5, 12, 8, 130, 44];
const index = numbers.findIndex(num => num > 10);
console.log(index); // 1 (found at position 1)
const notFoundIndex = numbers.findIndex(num => num > 200);
console.log(notFoundIndex); // -1 (not found)
// Remove item from array by ID
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
];
const indexToRemove = users.findIndex(user => user.id === 2);
if (indexToRemove !== -1) {
users.splice(indexToRemove, 1);
}
console.log(users); // Alice and Charlie remain
---
Part 7: The some() Method
some() checks if at least one element passes a test.
const numbers = [1, 3, 5, 7, 8];
// Are any numbers even?
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true (8 is even)
// Are any numbers negative?
const hasNegative = numbers.some(num => num < 0);
console.log(hasNegative); // false
// Check if any user is admin
const users[] = [
{ name: "Alice", isAdmin: false },
{ name: "Bob", isAdmin: true },
{ name: "Charlie", isAdmin: false }
];
const hasAdmin = users.some(user => user.isAdmin);
console.log(hasAdmin); // true
---
Part 8: The every() Method
every() checks if all elements pass a test.
const numbers = [2, 4, 6, 8, 10];
// Are all numbers even?
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // true
const numbers2 = [2, 4, 5, 8];
const allEven2 = numbers2.every(num => num % 2 === 0);
console.log(allEven2); // false (5 is odd)
// Check if all users are adults
const users[] = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 35 }
];
const allAdults = users.every(user => user.age >= 18);
console.log(allAdults); // true
---
Part 9: Method Chaining
You can chain array methods together:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Get even numbers, double them, then sum them
const result = numbers
.filter(num => num % 2 === 0) // [2, 4, 6, 8, 10]
.map(num => num * 2) // [4, 8, 12, 16, 20]
.reduce((sum, num) => sum + num, 0); // 60
console.log(result); // 60
Real-World Example
const products[] = [
{ name: "Laptop", price: 999, category: "electronics", inStock: true },
{ name: "Mouse", price: 25, category: "electronics", inStock: true },
{ name: "Desk", price: 200, category: "furniture", inStock: false },
{ name: "Chair", price: 150, category: "furniture", inStock: true },
{ name: "Keyboard", price: 75, category: "electronics", inStock: true }
];
// Get names of in-stock electronics under $100
const affordableElectronics = products
.filter(p => p.category === "electronics")
.filter(p => p.inStock)
.filter(p => p.price < 100)
.map(p => p.name);
console.log(affordableElectronics); // ["Mouse", "Keyboard"]
// Calculate total value of in-stock items
const totalValue = products
.filter(p => p.inStock)
.reduce((sum, p) => sum + p.price, 0);
console.log(`Total value: $${totalValue}`); // Total value: $1249
---
Part 10: Comparison with Traditional Loops
Using Loops (Old Way)
const numbers = [1, 2, 3, 4, 5];
// Double even numbers
const result = [];
for (const num of numbers) {
if (num % 2 === 0) {
result.push(num * 2);
}
}
console.log(result); // [4, 8]
Using Array Methods (Modern Way)
const numbers = [1, 2, 3, 4, 5];
const result = numbers
.filter(num => num % 2 === 0)
.map(num => num * 2);
console.log(result); // [4, 8]
Benefits of array methods:
- More concise and readable
- No need to manage temporary variables
- Less prone to errors
- Functional programming style
- Each method returns a new array (immutability)
---
Practice Exercises
Exercise 1: Student Grades
Given an array of student objects with grades, find the average grade of passing students (grade >= 60).
Exercise 2: Product Filter
Filter products by multiple criteria and calculate total discounted price.
Exercise 3: Word Statistics
Count words, find longest word, and filter words by length from a text string.
Exercise 4: Data Transformation
Transform an array of users into a lookup object (dictionary) with ID as key.
Exercise 5: Shopping Cart
Implement cart operations: add, remove, update quantity, calculate total, apply discount.
Exercise 6: Array Flattening
Flatten a deeply nested array using reduce.
---
Common Mistakes
Mistake 1: Forgetting to Return in map/filter
const numbers = [1, 2, 3];
// ❌ WRONG - No return
const doubled = numbers.map(num => {
num * 2; // Missing return!
});
console.log(doubled); // [undefined, undefined, undefined]
// ✅ CORRECT
const doubled = numbers.map(num => {
return num * 2;
});
// OR (implicit return with arrow functions)
const doubled = numbers.map(num => num * 2);
Mistake 2: Mutating Original Array
const numbers = [1, 2, 3];
// ❌ DON'T DO THIS - mutates original
numbers.forEach(num => {
num = num * 2; // Doesn't change array!
});
// ✅ CORRECT - use map for transformation
const doubled = numbers.map(num => num * 2);
Mistake 3: Wrong Initial Value in reduce
const numbers = [1, 2, 3];
// ❌ WRONG - No initial value, could cause issues
const sum = numbers.reduce((acc, num) => acc + num);
// ✅ CORRECT - Always provide initial value
const sum = numbers.reduce((acc, num) => acc + num, 0);
---
Key Concepts Summary
| Method | Returns | Purpose |
|---|---|---|
| map() | New array | Transform each element |
| filter() | New array | Select elements that pass test |
| reduce() | Single value | Combine elements into one value |
| find() | Element or undefined | Find first match |
| findIndex() | Number | Find index of first match |
| some() | Boolean | Check if any element passes |
| every() | Boolean | Check if all elements pass |
What You Learned
- ✅ How to transform arrays with
map() - ✅ How to filter arrays with
filter() - ✅ How to reduce arrays to single values with
reduce() - ✅ How to find elements with
find()andfindIndex() - ✅ How to test arrays with
some()andevery() - ✅ How to chain methods for complex operations
- ✅ When to use array methods vs traditional loops
What's Next?
In the next lesson, you'll learn about error handling - how to deal with errors gracefully using try/catch blocks and create your own custom errors!