Есть массив из чисел на 11 элементов:
let arr = [1,2,3,4,5,6,7,8,9,10,11];
Мы хотим получить массив из массивов, так, чтобы вложенные массивы хранили в себе по три элемента оригинального массива, начиная с начала. Если элементов недостаточно в конце массива, то всё равно добавляем те что есть, в пределах до 3 штук.
Это довольно частая задача. Например для группировок товаров по несколько штук на страницах пагинации. Как это сделать?
Разделение массива по 3 элемента при помощи функции-генератора в JavaScript
В JavaScript существуют такие специальные функции, которые умеют выполнять часть логики своей работы (можно сказать выполнять «по шагам», останавливая своё выполнение на каждом шаге). Они называются «функциями-генераторами«. В момент её вызова создаётся специальный объект «Генератор» (экземпляр класса Generator), который при помощи метода «next()
» умеет возвращать промежуточный результат работы функции (например если внутри неё работает цикл).
Каждый вызов метода «next()
» выдаёт только один промежуточный результат вычислений. Возврат промежуточного значения из функции-генератора осуществляется при помощи ключевого слова «yield
» — записывается в теле функции-генератора.
Синтаксически, функция оформляется в виде «function*
«. Обязательно звёздочка после слова «function».
function* chunks(arr, n) { for (let i = 0; i < arr.length; i += n) { yield arr.slice(i, i + n); } }
Этот генератор является универсальным для получения не только по 3 элемента, но и под любое целое число (например 2 или 5). Обратите внимание, в нём нет ключевого слова «return«.
Мы будем передавать в этот генератор два параметра:
- Массив, который нужно разделить на группы — «arr«
- Количество элементов в группе на которые нужно делить весь массив «n«
Как использовать функцию-генератор для решения задачи по разделению массива по 3 элемента в JavaScript?
В JavaScript многие элементы языка хорошо продуманы для общения друг с другом. Это фундаментальный уровень, который должен работать в любой среде выполнения кода.
Мы можем использовать «spread-оператор» троеточия и литеральное обозначение массива, чтобы распаковать в этот новый массив все промежуточные результаты, которые выдаст нам генератор.
Важно отметить, что spread-оператор работает только с итерируемыми объектами.
[...chunks(arr, 3)]
Результат:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]
Скриншот из консоли браузера:

Вызов функции-генератора и сохранение объекта генератора в переменную с именем gen в JavaScript
Предлагаю посмотреть на то, какой этап мы не видим, когда используем «spread-оператор троеточия«. Давайте создадим переменную «gen«, в которую сохраним наш объект генератора.
let gen = chunks(arr, 3)
Смотрим, что теперь хранится в «gen«.

Согласно документации ECMAScript, все экземпляры Генераторов наследуют 3 метода для работы с ним:
- next ( value )
- return ( value )
- throw ( exception )
Для получения следующего итерируемого значения мы используем метод «next()«. Делаем первый вызов метода:
gen.next()
Что получаем?

Нам возвращается объект в ключами «done» и «value«.
Ключ «done» со значением false, говорит нам о том, что генератор не завершил свою работу и есть ещё элементы для следующего вызова.
Ключ «value» хранит в себе заветное значение первого результата обхода нашего массива.
Если вернуться к работе «spread-оператора«, то он умеет работать с объектами подобного вида. Грубо говоря «под капотом» он делает вызовы метода «next()» и извлекает значения из «value» до тех пор, пока «done» является false.
Именно этот момент нужно было прояснить.
Теперь можем проделать остальные вызовы, когда «done» станет равным true.

Когда «done» станет равным true, тогда в «value» перестанут появляться значения. Будет всегда undefined.