Глиф Учебники

Урок 7. Массивы и методы map, filter, reduce

Курс «JavaScript» · урок 7 из 10 · 4 минуты чтения

Массив — упорядоченный список значений. Список покупок, оценки в журнале, товары в корзине — всё это массивы. Элементы пишутся в квадратных скобках через запятую, и у каждого есть номер — индекс.

Создание и обращение к элементам

JavaScript
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
индекс 0 1 2 10 fruits "яблоко" "груша" "слива" … нет fruits.length = 3 fruits[0] "яблоко" первый fruits[fruits.length - 1] "слива" последний: индекс 3 − 1 = 2 fruits[10] undefined за пределами — не ошибка
Индексы массива fruits идут с нуля: у первого элемента индекс 0, у последнего — fruits.length - 1, то есть 2, а элемента с индексом 10 нет, и обращение к нему даёт undefined.

Node.js выводит массив в квадратных скобках со строками в одинарных кавычках. Консоль браузера показывает тот же массив немного иначе — например, (3) ['яблоко', 'груша', 'слива'], с длиной впереди.

Элемент можно заменить: fruits[1] = "персик". Массив, объявленный через const, при этом менять можно — const запрещает только записать в переменную другой массив целиком.

Добавить и удалить

Действия с массивом записывают через точку после его имени: list.push("г"). Такие функции, которые принадлежат значению, называют методами.

JavaScript
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

Все они меняют сам массив. Как удалить элемент по значению — в справке Как удалить элемент из массива.

Поиск

JavaScript
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
1

Кусок массива, строка из массива и обратно

JavaScript
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
[ 'раз', 'два', 'три' ]

Перебор: forEach

forEach вызывает функцию для каждого элемента — то же, что цикл for...of, только записанное методом. Функция получает элемент и его индекс:

JavaScript
const colors = ["красный", "зелёный"];

colors.forEach((color, i) => {
  console.log(i + ": " + color);
});
Вывод
0: красный
1: зелёный

map, filter, reduce

Три главных метода массивов. Каждый принимает функцию (callback — из урока о функциях) и не меняет исходный массив, а возвращает новый результат.

JavaScript
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 ]
numbers исходный — не меняется 3 8 1 10 5 .map((n) => n * 2) каждый элемент — новый 6 16 2 20 10 .filter((n) => n > 4) только подходящие 8 10 5 .reduce((acc, n) => acc + n, 0) всё в одно значение 0 + 3 + 8 + 1 + 10 + 5 = 27
Из массива numbers map делает новый массив той же длины с удвоенными числами, filter оставляет только числа больше 4, а reduce складывает всё, начиная с 0, в одно число 27.

Как reduce считает сумму, по шагам:

ШагaccnВернула функция
1033
23811
311112
4121022
522527

Начальное значение лучше указывать всегда: без него reduce на пустом массиве выдаёт ошибку.

Методы можно ставить цепочкой — результат одного сразу передаётся следующему:

JavaScript
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

JavaScript
const ages = [15, 22, 17];
console.log(ages.some((a) => a >= 18));
console.log(ages.every((a) => a >= 18));
Вывод
true
false

Сортировка: ловушка с числами

sort() без аргументов сортирует элементы как строки. Для слов это то, что нужно, а для чисел — нет:

JavaScript
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 ]
const nums = [10, 9, 1, 25]; [...nums].sort() сравнивает как строки — по первому символу "1" "10" "25" "9" [ 1, 10, 25, 9 ] — не по величине [...nums].sort((a, b) => a - b) сравнивает числа 1 9 10 25 [ 1, 9, 10, 25 ]
Без функции sort сравнивает числа как строки, по первому символу, и "25" встаёт раньше "9"; с функцией (a, b) => a - b числа идут по возрастанию: 1, 9, 10, 25.

Числа сортируют с функцией сравнения: (a, b) => a - b — по возрастанию, (a, b) => b - a — по убыванию. Функция возвращает отрицательное число, если a должно стоять раньше b, и положительное — если позже.

sort меняет сам массив. Здесь сортируется копия: [...nums] — новый массив с теми же элементами (три точки «раскладывают» массив на элементы). Так исходный nums остаётся как был.

Коротко

Проверьте себя

1. Что выведет console.log(["a", "b", "c"][1])?
2. Какой метод вернёт новый массив только с чётными числами?
3. Что выведет программа?
JavaScript
console.log([5, 20, 100].sort());
4. Чему равно [1, 2, 3, 4].reduce((acc, n) => acc + n, 10)?