Style - How to write meaningful comments
You've already learned basic array operations like push(), pop(), and slice(). Now it's time to level up with array methods: powerful functions that transform how you work with collections of data.
Think about what you currently do with loops:
// Find all products over €50
const expensive = [];
for (let i = 0; i < products.length; i++) {
if (products[i].price > 50) {
expensive.push(products[i]);
}
}
// Double all prices
const doubled = [];
for (let i = 0; i < prices.length; i++) {
doubled.push(prices[i] * 2);
}
// Calculate total
let total = 0;
for (let i = 0; i < prices.length; i++) {
total += prices[i];
}
Array methods let you express these operations declaratively: you describe what you want, not how to get it:
// Find all products over €50
const expensive = products.filter(p => p.price > 50);
// Double all prices
const doubled = prices.map(price => price * 2);
// Calculate total
const total = prices.reduce((sum, price) => sum + price, 0);
Same results, dramatically less code. More importantly, the intent is crystal clear.
These methods are fundamental to modern JavaScript. They're used everywhere: frontend frameworks like React, backend code in Node.js, data processing. Master them and you'll write cleaner, more maintainable code that other developers instantly understand.
<aside> 💡
Array methods don't modify the original array (except sort()). They return new arrays, making your code safer and more predictable. This concept is called "immutability" and is a cornerstone of modern JavaScript.
</aside>
https://www.youtube.com/watch?v=R8rmfD9Y5-c
What you'll learn:
map() - Transform every elementforEach() - Call a function once for each array elementfilter() - Select matching elementsfind() - Get the first matchevery() / some() - Test conditionssort() - Reorder elementsreduce() - Combine into any valueCreates a new array by applying a function to each element.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8]
// Extract properties
const users = [
{ name: 'Alice', age: 28 },
{ name: 'Bob', age: 32 }
];
const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob']
// Transform objects
const withIds = users.map((user, index) => ({
id: index + 1,
...user
}));
Callback parameters:
element - Current itemindex - Current position (optional)array - Original array (optional)const numbered = ['a', 'b', 'c'].map((letter, index) => {
return `${index + 1}. ${letter}`;
});
// ['1. a', '2. b', '3. c']
<aside> 💡
map() always returns a new array with the same length as the original.
</aside>
Executes a function for each array element. Unlike map(), it doesn't return a new array: it's purely for side effects like logging or updating external state.
const numbers = [1, 2, 3, 4];
// Simple iteration
numbers.forEach(num => {
console.log(num);
});
// 1
// 2
// 3
// 4
// With index
const fruits = ['apple', 'banana', 'orange'];
fruits.forEach((fruit, index) => {
console.log(`${index + 1}. ${fruit}`);
});
// 1. apple
// 2. banana
// 3. orange
// Update external variable
let sum = 0;
numbers.forEach(num => {
sum += num;
});
console.log(sum); // 10
// Update DOM elements (in browser)
userElements.forEach(element => {
element.classList.add('active');
});
// Logging or debugging
users.forEach(user => {
console.log(`Processing user: ${user.name}`);
processUser(user);
});
<aside> 💡
Use forEach() when you need to perform an action for each element but don't need a new array. If you need to transform data, use map() instead.
</aside>
Creates a new array with elements that pass a test.
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6]
// Filter objects
const users = [
{ name: 'Alice', age: 28, active: true },
{ name: 'Bob', age: 32, active: false },
{ name: 'Charlie', age: 25, active: true }
];
const activeUsers = users.filter(user => user.active);
const adults = users.filter(user => user.age >= 30);
// Remove empty strings
const cleaned = data.filter(str => str.trim() !== '');
// Remove duplicates (with indexOf)
const unique = array.filter((item, index) =>
array.indexOf(item) === index
);
// Complex conditions
const filtered = products.filter(product =>
product.price > 20 && product.inStock && product.category === 'electronics'
);
Returns the first element that passes the test (or undefined).
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
const user = users.find(u => u.id === 2);
console.log(user); // { id: 2, name: 'Bob' }
const missing = users.find(u => u.id === 99);
console.log(missing); // undefined
// Find by property
const admin = users.find(u => u.role === 'admin');
// Find with complex logic
const eligible = applicants.find(a =>
a.age >= 18 && a.hasLicense && !a.hasCriminalRecord
);
// Check if found
if (user) {
console.log('Found:', user.name);
} else {
console.log('User not found');
}
<aside> 💡
Use find() when you need the element itself. Use findIndex() if you need its position.
</aside>
Returns true if all elements pass the test.
const numbers = [2, 4, 6, 8];
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // true
const hasOdd = [2, 3, 4].every(num => num % 2 === 0);
console.log(hasOdd); // false
const users = [
{ name: 'Alice', age: 28 },
{ name: 'Bob', age: 32 },
{ name: 'Charlie', age: 25 }
];
const allAdults = users.every(user => user.age >= 18);
const allHaveNames = users.every(user => user.name && user.name.length > 0);
if (allAdults && allHaveNames) {
console.log('All users valid');
}
Returns true if at least one element passes the test.
const numbers = [1, 3, 5, 8];
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true
const allOdd = [1, 3, 5].some(num => num % 2 === 0);
console.log(allOdd); // false
// Check if any user is admin
const hasAdmin = users.some(user => user.role === 'admin');
// Check if any item out of stock
const hasOutOfStock = products.some(p => p.stock === 0);
// Check if any error in validation
const hasErrors = validationResults.some(result => !result.valid);
<aside> ⌨️
Hands on: Given an array of numbers, use every() to check if all are positive, and some() to check if any are divisible by 10.
</aside>
// Numbers - WRONG (converts to strings)
const numbers = [10, 2, 30, 4];
numbers.sort();
console.log(numbers); // [10, 2, 30, 4] - alphabetical!
// Numbers - CORRECT (with compare function)
numbers.sort((a, b) => a - b);
console.log(numbers); // [2, 4, 10, 30]
// Descending
numbers.sort((a, b) => b - a);
console.log(numbers); // [30, 10, 4, 2]
// Strings (works by default)
const words = ['banana', 'apple', 'cherry'];
words.sort();
console.log(words); // ['apple', 'banana', 'cherry']
Compare function:
a should come before bb should come before a// Sort objects by property
const users = [
{ name: 'Charlie', age: 25 },
{ name: 'Alice', age: 28 },
{ name: 'Bob', age: 32 }
];
// By age
users.sort((a, b) => a.age - b.age);
// By name
users.sort((a, b) => a.name.localeCompare(b.name));
// Multiple criteria
users.sort((a, b) => {
if (a.active !== b.active) {
return a.active ? -1 : 1; // Active users first
}
return a.name.localeCompare(b.name); // Then by name
});
<aside> ⚠️
sort() modifies the original array in place. To keep the original, copy first: [...array].sort()
</aside>
Most powerful but complex. Reduces array to a single value by applying a function.
// Sum numbers
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 10
// Find maximum
const max = numbers.reduce((max, num) => num > max ? num : max, numbers[0]);
// Count occurrences
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const counts = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
// { apple: 3, banana: 2, orange: 1 }
// As an alternative, you can also use loops.
// Count occurrences (for...of)
const counts = {};
for (const fruit of fruits) {
counts[fruit] = (counts[fruit] || 0) + 1;
}
Tradeoffs between reduce and loops: reduce is concise and expressive for aggregations once you’re familiar with it, and it’s common in functional-style codebases. for...of is more explicit and often easier to read for beginners, with slightly less overhead; both have the same time and space complexity, so the choice is mainly about clarity and team conventions.
Parameters:
accumulator - Running total/resultcurrentValue - Current elementcurrentIndex - Position (optional)array - Original array (optional)// Build object from array
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const usersById = users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {});
// { 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' } }
// Flatten nested arrays
const nested = [[1, 2], [3, 4], [5]];
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
// [1, 2, 3, 4, 5]
// Group by property
const products = [
{ name: 'Laptop', category: 'electronics' },
{ name: 'Shirt', category: 'clothing' },
{ name: 'Phone', category: 'electronics' }
];
const grouped = products.reduce((acc, product) => {
const category = product.category;
if (!acc[category]) {
acc[category] = [];
}
acc[category].push(product);
return acc;
}, {});
// { electronics: [...], clothing: [...] }
<aside> 💡
</aside>