Введение в рекурсию
Чтобы узнать о рекурсии, нажмите здесь.
Нажмите здесь, чтобы опубликовать эту статью в LinkedIn »
Почему я только что потратил час, щелкая ссылку, которая просто возвращается на эту страницу ?!
Две причины:
- Это рекурсия.
- Надеюсь, это даст мне лучшую статистику.
Если вы не понимаете, почему это рекурсия, и действительно потратили час, нажимая на ту же ссылку, то цель этой статьи - понять эту шутку.
Зачем я это пишу?
Когда я учился развитию; Рекурсия всегда была одной из тех вещей, которые я вроде как понимал, думал, что это действительно здорово, но просто не мог найти для этого варианта использования.
Недавно я работал над проблемой, когда мне нужно было сгладить многомерные объекты в плоскую структуру. Это была проблема, которую легко разрешить с помощью рекурсии; и тот, который, как я думал, хорошо подойдет для публикации в блоге.
Итак, что мы строим?
Эта часть проста; мы напишем функцию, которая для многомерного объекта будет возвращать одномерный объект со всеми парами ключ-значение вложенных объектов.
Обратите внимание, что нас интересуют только ключи, с которыми на самом деле связано значение; не те, которые назначены вложенным объектам.
Функция
Давайте посмотрим на всю функцию, а затем обсудим каждый шаг вместе.
Давайте теперь пройдемся по этой строке за строкой.
- Создайте пустой объект, который мы добавим и вернем.
let obj = {};
2. Получите keys
из object
, переданных в функцию. Если бы у вас был объект {one: 1, two: 2, three: { four: 4 }}
, то ключи были бы one
, two
и three
(four
не вложен). Затем мы используем функцию forEach
для перебора каждого key
.
Object.keys(object).forEach(key => {});
3. Затем проверяем тип value
; если это не объект, мы добавляем его к нашему obj
Object и идем дальше.
if (typeof object[key] !== 'object') { obj[key] = object[key]; }
4. На следующем этапе мы используем рекурсию. Если тип value
- это объект (например, three: { four: 4 }
three - это key
, а его value
- это объект), то мы рекурсивно вызываем функцию flattenObject
, чтобы вернуть одномерный объект, который мы можем затем объединить с obj
else { obj = { ...obj, ...flattenObject(object[key]) }; }
Имеет смысл!
Нет, конечно же, нет! Даже я немного запутался. Давайте рассмотрим пункт 4 более подробно.
Вместо нашего большого объекта с несколькими уровнями вложенных объектов давайте начнем с более простого;
const obj = {one: 1, two: { three: 3}, four: 4}
Вот что происходит, когда мы передаем это нашей flattenObject
функции
obj
назначается пустому объекту- Массив возвращается из
Object.keys(object)
([one, two, four]
) - Затем мы перебираем этот массив, используя
forEach
- Первый ключ (
one
) имеет значение1
, которое не является объектом, поэтому оно добавляется кobj
. obj
теперь равно{one: 1}
- Второй ключ (
two
) имеет значение объекта, поэтому мы собираемся рекурсивно вызывать функциюflattenObject
. - Функция
flattenObject
вызывается сobject[key]
, который в этом примере равенobject[two]
и, следовательно,{three: 3 }
- Еще раз создается переменная (
obj
), равная пустому объекту ({}
). Важно отметить, что эта переменная полностью отличается от той, которая использовалась при первом вызове этой функции; каждый вызов занимает свое собственное место в стеке вызовов и, следовательно, имеет собственную область действия. - Массив возвращается из
Object.keys(object)
([three]
) - Затем мы перебираем этот массив, используя
forEach
(теперь вы должны начать видеть сходство с пунктами, указанными выше) - Первый ключ (
three
) имеет значение3
, которое не является объектом, поэтому оно добавляется кobj
. - В массиве больше нет элементов, которые можно было бы перебирать, поэтому возвращается
obj
. - Помня, что мы вызывали функцию рекурсивно, возвращенный объект затем передается в оператор распространения.
// Changing this obj = { ...obj, ...flattenObject(object[key]) }; // To this obj = { ...{one: 1}, ...{three: 3} };
- А поскольку оператор распространения объединяет два объекта вместе, obj теперь равно
{one: 1, three: 3}
- Третий ключ (
four
), помня, что переданный нами объект был{one: 1, two: { three: 3}, four: 4}
, имеет значение4
, которое не является объектом, поэтому оно добавляется кobj
. obj
теперь равно{one: 1, three: 3, four: 4}
.- В массиве больше нет элементов, которые можно было бы перебирать, поэтому возвращается
obj
.
Быстрое предупреждение
Хотя использование рекурсии может выглядеть действительно умно и приятно, его следует использовать с осторожностью. Помните, что каждый рекурсивный вызов добавляет еще один вызов в стек вызовов, который может взорваться вам прямо в лицо (превышен максимальный размер стека вызовов). Вам следует подумать о том, чтобы прочитать о хвостовой рекурсии, или, может быть, я напишу об этом еще один пост в блоге (следите за обновлениями!).
Вот и все
Вот как вы можете использовать рекурсию для преобразования многомерного объекта в одномерный объект. Вот еще раз код: