Кратко
СкопированоМетод flat
позволяет сформировать массив, применяя функцию к каждому элементу, затем уменьшает вложенность, делая этот массив плоским, и возвращает его.
Был добавлен в стандарте ES2019. Если вы поддерживаете браузеры, выпущенные раньше 2018 года, то вам понадобится полифил.
Пример
СкопированоПолучить плоский список из сложной структуры
СкопированоПредставим, что у нас есть список заказов пользователей из которого мы хотим понять, какие товары заказывают:
const orders = [ { id: 1, products: [ { name: 'Чизкейк', price: 1.99 }, { name: 'Бисквит', price: 4.99 }, ] }, { id: 2, products: [ { name: 'Шоколад', price: 5.59 }, { name: 'Зефир', price: 8.99 }, ] }]
const orders = [ { id: 1, products: [ { name: 'Чизкейк', price: 1.99 }, { name: 'Бисквит', price: 4.99 }, ] }, { id: 2, products: [ { name: 'Шоколад', price: 5.59 }, { name: 'Зефир', price: 8.99 }, ] } ]
Одним из решений будет сначала дважды вызвать метод map
, а затем сделать массив плоским с помощью метода flat
Сначала воспользуемся методом map
:
orders.map( (order) => order.products.map(product => product.name))
orders.map( (order) => order.products.map(product => product.name) )
Получим следующий результат:
[['Чизкейк', 'Бисквит'], ['Шоколад', 'Зефир']]
[['Чизкейк', 'Бисквит'], ['Шоколад', 'Зефир']]
Обратите внимание на вложенность массивов, нам нужно от неё избавиться. Для этого применим метод flat
:
orders .map((order) => order.products.map((product) => product.name)) .flat()
orders .map((order) => order.products.map((product) => product.name)) .flat()
['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']
['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']
Другое решение этой задачи — сразу вызвать метод flat
(ведь статья у нас именно про него):
orders.flatMap( (order) => order.products.map(product => product.name))
orders.flatMap( (order) => order.products.map(product => product.name) )
Увидим что функция применилась, вложенность уменьшилась и мы получили только названия продуктов из массива products
:
['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']
['Чизкейк', 'Бисквит', 'Шоколад', 'Зефир']
Модификация структуры данных
СкопированоПредставим, что мы пишем корзину для интернет-магазина. Товары в корзине храним в виде объекта:
const cart = [ { name: 'Телефон', count: 1, price: 500, }, { name: 'Ноутбук', count: 1, price: 800, }]
const cart = [ { name: 'Телефон', count: 1, price: 500, }, { name: 'Ноутбук', count: 1, price: 800, } ]
Если человек покупает телефон, то требуется добавить зарядное устройство. Для этого вызовем flat
и будем возвращать массив из телефона и зарядного устройства вместо одного объекта с телефоном.
cart.flatMap( (item) => { if (item.name === 'Телефон') { return [item, { name: 'Зарядное устройство', count: item.count, price: 50, }] } return item })
cart.flatMap( (item) => { if (item.name === 'Телефон') { return [item, { name: 'Зарядное устройство', count: item.count, price: 50, }] } return item } )
flat
сделает массив плоским и мы получим массив элементов в корзине:
[ { name:'Телефон', count:1, price:500, }, { name:'Зарядное устройство', count:1, price:50, }, { name:'Ноутбук', count:1, price:800, },]
[ { name:'Телефон', count:1, price:500, }, { name:'Зарядное устройство', count:1, price:50, }, { name:'Ноутбук', count:1, price:800, }, ]
Эту же задачу можно решить и другим способом, применив метод reduce
. Но это отразится на читаемости кода, а этим пренебрегать не стоит!
cart.reduce((list, item) => { if (item.name === 'Телефон') { list.push(item, { name: 'Зарядное устройство', count: item.count, price: 50, }) } else { list.push(item) } return list}, [])
cart.reduce((list, item) => { if (item.name === 'Телефон') { list.push(item, { name: 'Зарядное устройство', count: item.count, price: 50, }) } else { list.push(item) } return list }, [])
Как пишется
СкопированоКак и другим похожим методам, flat
необходимо передать колбэк-функцию, которая будет возвращать какое-то значение. Именно это значение попадёт в итоговый массив.
Функция, которую мы передаём в flat
, принимает три аргумента:
current
— текущий элемент массива.Value index
— индекс текущего элемента в массиве.array
— массив, который мы перебираем.
Возвращает 0 или более элементов массива.
Как понять
СкопированоМетод идентичен последовательному вызову map
с параметром depth
, соответственно, применяется для трансформации исходных данных, с уменьшением вложенности.
Данный метод более эффективный, чем вызов этих функций по отдельности, поскольку обход массива совершается только один раз.
Разница между map()
и flatMap()
СкопированоРассмотрим на примере разницу между методами map
и flat
. Возьмём массив с данными о местоположении и представим, что нужно получить (или преобразовать) координаты:
const allActivities = [ { title: 'Офис', coordinates: [50.123, 3.291] }, { title: 'Спортзал', coordinates: [1.238, 4.292] },]const mappedCoordinates = allActivities.map(activity => activity.coordinates)const flatMappedCoordinates = allActivities.flatMap(activity => activity.coordinates)
const allActivities = [ { title: 'Офис', coordinates: [50.123, 3.291] }, { title: 'Спортзал', coordinates: [1.238, 4.292] }, ] const mappedCoordinates = allActivities.map(activity => activity.coordinates) const flatMappedCoordinates = allActivities.flatMap(activity => activity.coordinates)
Теперь взглянем на результаты с применением map
:
[[50.123, 3.291], [1.238, 4.292]]
[[50.123, 3.291], [1.238, 4.292]]
И на результат с flat
:
[50.123, 3.291, 1.238, 4.292]
[50.123, 3.291, 1.238, 4.292]
Вместо того чтобы использовать метод map
и получить массивы координат, а затем сократить массив, вы можете сразу использовать flat
.
Разница между flat() и flatMap()
СкопированоМетод flat
делает входной массив плоским, глубина указывается в аргументах.
Метод flat
применяет функцию, трансформируя массив и делает массив плоским. Два в одном.