JavaScript · Синтаксис · Промежуточный

Методы массивов: map, filter, reduce

10 задач

Функциональные методы массивов для преобразования, фильтрации и агрегации данных без явных циклов.

map, filter, reduce, forEach: неявный return и предупреждения о мутации

#
**map — преобразовать каждый элемент** ```javascript const nums = [1, 2, 3, 4]; // map возвращает НОВЫЙ массив — оригинал не изменяет const doubled = nums.map(x => x * 2); // [2, 4, 6, 8] console.log(nums); // [1, 2, 3, 4] — не изменён // Callback map получает (element, index, array): const tagged = nums.map((x, i) => `${i}:${x}`); // ['0:1', '1:2', '2:3', '3:4'] // Частая ошибка — забыть неявный return в стрелочных функциях: const bad = nums.map(x => { x * 2 }); // [undefined, ...] — {} означает блок const good = nums.map(x => x * 2); // [2, 4, 6, 8] — тело-выражение const good2 = nums.map(x => ({ value: x * 2 })); // объект — оберни в () ``` **filter — оставить элементы, прошедшие тест** ```javascript const evens = nums.filter(x => x % 2 === 0); // [2, 4] // filter тоже возвращает новый массив: const words = ['', 'hello', null, 'world', undefined]; const clean = words.filter(Boolean); // ['hello', 'world'] — убирает ложные значения ``` **reduce — свернуть в одно значение** ```javascript // reduce(callback, initialValue) // callback получает (accumulator, currentValue, index, array) const sum = nums.reduce((acc, x) => acc + x, 0); // 10 const max = nums.reduce((acc, x) => x > acc ? x : acc, -Infinity); // 4 // Всегда предоставляй начальное значение — без него reduce падает на пустом массиве: [].reduce((acc, x) => acc + x); // TypeError: Reduce of empty array [].reduce((acc, x) => acc + x, 0); // 0 — безопасно ``` **forEach — только побочные эффекты** ```javascript // forEach возвращает undefined — никогда не используй для построения нового массива nums.forEach(x => console.log(x)); // выводит 1 2 3 4 // ПЛОХО: const result = nums.forEach(x => x * 2); // undefined — не делай так // ХОРОШО: используй map когда нужен новый массив ``` **Предупреждение о мутации: sort() и reverse() изменяют массив** ```javascript const arr = [3, 1, 4, 1, 5]; // sort и reverse МУТИРУЮТ оригинал: arr.sort((a, b) => a - b); // arr теперь [1, 1, 3, 4, 5] arr.reverse(); // arr теперь [5, 4, 3, 1, 1] // Сортировать без мутации (ES2023 toSorted/toReversed, или сначала копировать): const sorted = [...arr].sort((a, b) => a - b); // безопасно — spread копирует const rev = arr.toReversed(); // ES2023, возвращает новый массив ```

Цепочки методов, reduce для группировки, flatMap и Array.from

#
**Цепочки методов массива** Так как map/filter возвращают новые массивы, их можно объединять в цепочку: ```javascript const users = [ { name: 'Alice', age: 25, active: true }, { name: 'Bob', age: 17, active: true }, { name: 'Carol', age: 32, active: false }, { name: 'Dave', age: 28, active: true }, ]; const result = users .filter(u => u.active && u.age >= 18) // оставить активных совершеннолетних .map(u => u.name) // извлечь имена .sort(); // по алфавиту // ['Alice', 'Dave'] ``` **reduce для группировки** ```javascript const orders = [ { category: 'food', amount: 30 }, { category: 'tech', amount: 200 }, { category: 'food', amount: 15 }, ]; const totals = orders.reduce((acc, order) => { acc[order.category] = (acc[order.category] ?? 0) + order.amount; return acc; }, {}); // { food: 45, tech: 200 } ``` **flatMap — преобразовать, затем разгладить на один уровень** ```javascript const sentences = ['hello world', 'foo bar baz']; // map даёт массив массивов: sentences.map(s => s.split(' ')); // [['hello','world'], ['foo','bar','baz']] // flatMap преобразует, затем разглаживает на один уровень: sentences.flatMap(s => s.split(' ')); // ['hello', 'world', 'foo', 'bar', 'baz'] // flatMap полезен для вывода переменного количества элементов: const nums = [1, 2, 3]; nums.flatMap(x => x % 2 === 0 ? [x, x * 10] : [x]); // [1, 2, 20, 3] ``` **Array.from — создать массив из других вещей** ```javascript // Из NodeList (DOM-элементы) Array.from(document.querySelectorAll('li')) .map(el => el.textContent); // Из Set (дедупликация) const unique = Array.from(new Set([1, 2, 2, 3, 3])); // [1, 2, 3] // Из строки Array.from('hello'); // ['h', 'e', 'l', 'l', 'o'] // С функцией отображения (второй аргумент): Array.from({ length: 5 }, (_, i) => i * 2); // [0, 2, 4, 6, 8] ```

find/some/every, flat, справочник мутаций, includes vs indexOf

#
**find, findIndex, some, every** ```javascript const users = [ { id: 1, name: 'Alice', age: 25 }, { id: 2, name: 'Bob', age: 17 }, { id: 3, name: 'Carol', age: 32 }, ]; // find — первое совпадение или undefined users.find(u => u.id === 2); // { id: 2, name: 'Bob', age: 17 } users.find(u => u.age > 50); // undefined // findIndex — индекс первого совпадения или -1 users.findIndex(u => u.name === 'Carol'); // 2 // some — true если хотя бы одно совпадает users.some(u => u.age < 18); // true (Бобу 17) // every — true если все совпадают users.every(u => u.age >= 18); // false (Бобу 17) ``` **flat и flat(Infinity)** ```javascript const nested = [1, [2, 3], [4, [5, 6]]]; nested.flat(); // [1, 2, 3, 4, [5, 6]] — один уровень nested.flat(2); // [1, 2, 3, 4, 5, 6] — два уровня nested.flat(Infinity); // полное разглаживание, любая глубина ``` **Справочник: мутация vs неизменность** ``` Метод Возвращает новый массив? Мутирует оригинал? ────────────── ────────────────────── ───────────────── map ✅ новый массив ❌ нет filter ✅ новый массив ❌ нет reduce ✅ одно значение ❌ нет flatMap ✅ новый массив ❌ нет flat ✅ новый массив ❌ нет slice ✅ новый массив ❌ нет concat ✅ новый массив ❌ нет sort ⚠ та же ссылка ✅ да — сортирует на месте reverse ⚠ та же ссылка ✅ да — разворачивает на месте splice возвращает удалённые ✅ да — изменяет массив push/pop возвращает элемент/длину ✅ да shift/unshift возвращает элемент/длину ✅ да fill ⚠ та же ссылка ✅ да toSorted ✅ новый массив ❌ нет (ES2023) toReversed ✅ новый массив ❌ нет (ES2023) ``` **includes, indexOf, at** ```javascript [1, 2, 3].includes(2); // true [1, 2, NaN].includes(NaN); // true (в отличие от indexOf!) [1, 2, 3].indexOf(2); // 1 [1, 2, NaN].indexOf(NaN); // -1 (использует ===, NaN !== NaN) // at() — поддержка отрицательного индекса const arr = [10, 20, 30, 40]; arr.at(-1); // 40 — последний элемент arr.at(-2); // 30 — предпоследний ```
01

Удвоить значения

#

Напишите функцию, которая принимает массив чисел и возвращает новый массив, где каждое число удвоено. Используйте метод map().

function doubleValues(numbers) {

}

console.log(doubleValues([1, 2, 3, 4, 5]));
Решение
function doubleValues(numbers) {
    return numbers.map(n => n * 2);
}

console.log(doubleValues([1, 2, 3, 4, 5]));
02

Оставить положительные

#

Напишите функцию, которая принимает массив чисел и возвращает только положительные. Используйте метод filter().

function keepPositives(numbers) {

}

console.log(keepPositives([3, -1, 4, -1, -5, 9, -2, 6]));
Решение
function keepPositives(numbers) {
    return numbers.filter(n => n > 0);
}

console.log(keepPositives([3, -1, 4, -1, -5, 9, -2, 6]));
03

Сумма массива

#

Напишите функцию, которая принимает массив чисел и возвращает их сумму. Используйте метод reduce().

function sumArray(numbers) {

}

console.log(sumArray([1, 2, 3, 4, 5]));
Решение
function sumArray(numbers) {
    return numbers.reduce((acc, n) => acc + n, 0);
}

console.log(sumArray([1, 2, 3, 4, 5]));
04

Слова длиннее N

#

Напишите функцию, которая принимает массив строк и минимальную длину и возвращает только строки длиннее этой длины.

function longWords(words, minLength) {

}

console.log(longWords(["cat", "elephant", "dog", "hippopotamus"], 4));
Решение
function longWords(words, minLength) {
    return words.filter(w => w.length > minLength);
}

console.log(longWords(["cat", "elephant", "dog", "hippopotamus"], 4));
05

Имена в верхнем регистре

#

Напишите функцию, которая принимает массив строк и возвращает новый массив, где каждая строка переведена в верхний регистр.

function toUpperCase(words) {

}

console.log(toUpperCase(["hello", "world", "javascript"]));
Решение
function toUpperCase(words) {
    return words.map(w => w.toUpperCase());
}

console.log(toUpperCase(["hello", "world", "javascript"]));
06

Произведение массива

#

Напишите функцию, которая принимает массив чисел и возвращает произведение всех элементов (перемножает их все). Используйте reduce().

function product(numbers) {

}

console.log(product([1, 2, 3, 4, 5]));
Решение
function product(numbers) {
    return numbers.reduce((acc, n) => acc * n, 1);
}

console.log(product([1, 2, 3, 4, 5]));
07

Извлечь свойство

#

Напишите функцию, которая принимает массив объектов со свойством `name` и возвращает массив только имён.

function getNames(people) {

}

const people = [
    { name: "Alice", age: 30 },
    { name: "Bob", age: 25 },
    { name: "Carol", age: 35 },
];
console.log(getNames(people));
Решение
function getNames(people) {
    return people.map(p => p.name);
}

const people = [
    { name: "Alice", age: 30 },
    { name: "Bob", age: 25 },
    { name: "Carol", age: 35 },
];
console.log(getNames(people));
08

Цепочка: filter потом map

#

Напишите функцию, которая принимает массив чисел, оставляет только те, что больше 10, и возвращает квадраты оставшихся чисел.

function squaresAboveTen(numbers) {

}

console.log(squaresAboveTen([3, 15, 8, 20, 5, 12]));
Решение
function squaresAboveTen(numbers) {
    return numbers
        .filter(n => n > 10)
        .map(n => n ** 2);
}

console.log(squaresAboveTen([3, 15, 8, 20, 5, 12]));
09

Подсчёт по условию

#

Напишите функцию, которая принимает массив чисел и возвращает количество чётных среди них.

function countEven(numbers) {

}

console.log(countEven([1, 2, 3, 4, 5, 6, 7, 8]));
Решение
function countEven(numbers) {
    return numbers.filter(n => n % 2 === 0).length;
}

console.log(countEven([1, 2, 3, 4, 5, 6, 7, 8]));
10

Группировка по первой букве

#

Напишите функцию, которая принимает массив строк и возвращает объект, где каждый ключ — первая буква, а значение — массив всех слов, начинающихся с этой буквы.

function groupByFirstLetter(words) {

}

const result = groupByFirstLetter(["apple", "banana", "avocado", "blueberry", "cherry"]);
console.log(result);
Решение
function groupByFirstLetter(words) {
    return words.reduce((acc, word) => {
        const letter = word[0];
        if (!acc[letter]) acc[letter] = [];
        acc[letter].push(word);
        return acc;
    }, {});
}

const result = groupByFirstLetter(["apple", "banana", "avocado", "blueberry", "cherry"]);
console.log(result);