Урок 7. Массивы и методы map, filter, reduce
Массив — упорядоченный список значений. Список покупок, оценки в журнале, товары в корзине — всё это массивы. Элементы пишутся в квадратных скобках через запятую, и у каждого есть номер — индекс.
Создание и обращение к элементам
const fruits = ["яблоко", "груша", "слива"];
console.log(fruits);
console.log(fruits.length);
console.log(fruits[0]);
console.log(fruits[fruits.length - 1]);
console.log(fruits[10]);[ 'яблоко', 'груша', 'слива' ]
3
яблоко
слива
undefined- Индексы начинаются с нуля: первый элемент —
fruits[0], последний —fruits[fruits.length - 1]. length— количество элементов.- Обращение за пределы массива — не ошибка, а
undefined.
Node.js выводит массив в квадратных скобках со строками в одинарных кавычках. Консоль браузера показывает тот же массив немного иначе — например, (3) ['яблоко', 'груша', 'слива'], с длиной впереди.
Элемент можно заменить: fruits[1] = "персик". Массив, объявленный через const, при этом менять можно — const запрещает только записать в переменную другой массив целиком.
Добавить и удалить
Действия с массивом записывают через точку после его имени: list.push("г"). Такие функции, которые принадлежат значению, называют методами.
const list = ["б", "в"];
list.push("г");
list.unshift("а");
console.log(list);
const last = list.pop();
const first = list.shift();
console.log(last, first);
console.log(list);[ 'а', 'б', 'в', 'г' ]
г а
[ 'б', 'в' ]| Метод | Что делает |
|---|---|
push(x) | добавляет в конец |
pop() | удаляет последний и возвращает его |
unshift(x) | добавляет в начало |
shift() | удаляет первый и возвращает его |
splice(i, n) | удаляет n элементов, начиная с индекса i |
Все они меняют сам массив. Как удалить элемент по значению — в справке Как удалить элемент из массива.
Поиск
const nums = [4, 7, 12, 7];
console.log(nums.includes(12));
console.log(nums.indexOf(7));
console.log(nums.indexOf(100));
console.log(nums.find((n) => n > 5));
console.log(nums.findIndex((n) => n > 5));true
1
-1
7
1includes(x)— есть ли значение в массиве:trueилиfalse.indexOf(x)— индекс первого такого значения или-1, если его нет.find(функция)— первый элемент, для которого функция вернулаtrue(илиundefined, если такого нет).findIndex— то же, но возвращает индекс.
Кусок массива, строка из массива и обратно
const letters = ["a", "b", "c", "d", "e"];
console.log(letters.slice(1, 3));
console.log(letters.join("-"));
const words = "раз два три".split(" ");
console.log(words);[ 'b', 'c' ]
a-b-c-d-e
[ 'раз', 'два', 'три' ]slice(начало, конец)— копия части массива от индексаначалодоконец, не включая его. Сам массив не меняется (в отличие от похожего по имениsplice).join(разделитель)склеивает элементы в строку,split(разделитель)— наоборот, режет строку на массив.
Перебор: forEach
forEach вызывает функцию для каждого элемента — то же, что цикл for...of, только записанное методом. Функция получает элемент и его индекс:
const colors = ["красный", "зелёный"];
colors.forEach((color, i) => {
console.log(i + ": " + color);
});0: красный
1: зелёныйmap, filter, reduce
Три главных метода массивов. Каждый принимает функцию (callback — из урока о функциях) и не меняет исходный массив, а возвращает новый результат.
const numbers = [3, 8, 1, 10, 5];
const doubled = numbers.map((n) => n * 2);
const big = numbers.filter((n) => n > 4);
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(doubled);
console.log(big);
console.log(sum);
console.log(numbers);[ 6, 16, 2, 20, 10 ]
[ 8, 10, 5 ]
27
[ 3, 8, 1, 10, 5 ]map— преобразовать каждый элемент. Новый массив той же длины: на месте каждого элемента — то, что вернула функция.filter— отобрать. В новый массив попадают только элементы, для которых функция вернулаtrue.reduce— свернуть массив в одно значение: сумму, максимум, строку. Функция получает накопительaccи очередной элемент и возвращает новое значение накопителя. Второй аргументreduce(здесь0) — начальное значение накопителя.
Как reduce считает сумму, по шагам:
| Шаг | acc | n | Вернула функция |
|---|---|---|---|
| 1 | 0 | 3 | 3 |
| 2 | 3 | 8 | 11 |
| 3 | 11 | 1 | 12 |
| 4 | 12 | 10 | 22 |
| 5 | 22 | 5 | 27 |
Начальное значение лучше указывать всегда: без него reduce на пустом массиве выдаёт ошибку.
Методы можно ставить цепочкой — результат одного сразу передаётся следующему:
const marks = [5, 3, 4, 2, 5, 4];
const goodCount = marks.filter((m) => m >= 4).length;
const average = marks.reduce((acc, m) => acc + m, 0) / marks.length;
const text = marks.map((m) => "*".repeat(m)).join(" ");
console.log(goodCount);
console.log(average.toFixed(2));
console.log(text);4
3.83
***** *** **** ** ***** ****Проверки: some и every
some(функция)—true, если условие верно хотя бы для одного элемента.every(функция)—true, если условие верно для всех.
const ages = [15, 22, 17];
console.log(ages.some((a) => a >= 18));
console.log(ages.every((a) => a >= 18));true
falseСортировка: ловушка с числами
sort() без аргументов сортирует элементы как строки. Для слов это то, что нужно, а для чисел — нет:
const nums = [10, 9, 1, 25];
console.log([...nums].sort());
console.log([...nums].sort((a, b) => a - b));
console.log([...nums].sort((a, b) => b - a));[ 1, 10, 25, 9 ]
[ 1, 9, 10, 25 ]
[ 25, 10, 9, 1 ]Числа сортируют с функцией сравнения: (a, b) => a - b — по возрастанию, (a, b) => b - a — по убыванию. Функция возвращает отрицательное число, если a должно стоять раньше b, и положительное — если позже.
sort меняет сам массив. Здесь сортируется копия: [...nums] — новый массив с теми же элементами (три точки «раскладывают» массив на элементы). Так исходный nums остаётся как был.
Коротко
- Индексы — с нуля, последний элемент —
arr[arr.length - 1], за пределами —undefined. push/pop— конец,unshift/shift— начало,splice— середина; они меняют массив.includes,indexOf,find— поиск;slice— копия части;joinиsplit— массив и строка.map— преобразовать,filter— отобрать,reduce— свернуть в одно значение; исходный массив не меняется.- Числа сортируют так:
sort((a, b) => a - b).