Почему рекурсию плохо использовать при глубоком копировании

Ответ

Рекурсия при глубоком копировании может привести к переполнению стека вызовов при работе с глубоко вложенными структурами. Также она менее эффективна по памяти и производительности по сравнению с итеративными подходами.

Лучше использовать:

  1. JSON.parse(JSON.stringify(obj)) – просто, но не копирует функции/undefined
  2. Циклы или готовые библиотеки (lodash.cloneDeep)

Пример проблемы:

function deepCopy(obj) {
  if (typeof obj !== 'object') return obj;
  const copy = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    copy[key] = deepCopy(obj[key]); // Рекурсивный вызов
  }
  return copy;
}

// Может упасть при очень глубоком объекте
const obj = { a: {} };
let temp = obj;
for (let i = 0; i < 100000; i++) {
  temp.a = {};
  temp = temp.a;
}
deepCopy(obj); // Stack overflow!

Ответ 18+ 🔞

Да ты послушай, что за дичь творится с этим вашим рекурсивным копированием! Ну, в теории-то всё красиво: функция вызывает саму себя, пока не скопирует всё до последнего вложенного объекта. Выглядит, вроде, элегантно, ёпта.

Но на практике, чувак, это же пиздец! Представь себе объект, который вложен сам в себя, как матрёшка, только нахуй глубже — на сто тысяч уровней. Твоя рекурсивная функция начнёт копать, как крот ебаный, и на каком-то ходу её просто вырвет на стек вызовов! «Stack overflow!» — и привет, программа накрылась медным тазом. Во все дыры давалка, а тут — переполнение.

И по производительности это не фонтан. Память жрёт, как не в себя, каждый вызов — новые затраты. В общем, терпения ебать ноль на эту рекурсию, когда дело доходит до реально глубоких структур.

Так что, э, бошка думай! Есть же варианты попроще и понадёжнее:

  1. Старый добрый трюк с JSON. JSON.parse(JSON.stringify(obj)) — работает на ура для простых данных (числа, строки, массивы, объекты). Но, внимание, хитрая жопа: функции, undefined и циклические ссылки он благополучно проигнорирует. Как будто их и не было! Так что если они есть — это не вариант, пидарас шерстяной.

  2. Итеративные подходы или готовые библиотеки. Взять ту же lodash с её _.cloneDeep(obj). Там под капотом не тупая рекурсия, а умные обходы, которые и стек не переполнят, и с любыми типами данных разберутся. Просто, надёжно, без сюрпризов.

Вот смотри, наглядный пиздец:

function deepCopy(obj) {
  if (typeof obj !== 'object') return obj;
  const copy = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    copy[key] = deepCopy(obj[key]); // Рекурсивный вызов
  }
  return copy;
}

// А теперь создадим объект глубже, чем Марианская впадина
const obj = { a: {} };
let temp = obj;
for (let i = 0; i < 100000; i++) {
  temp.a = {};
  temp = temp.a;
}
deepCopy(obj); // Stack overflow! Пиздец и точка.

Вот и весь сказ, блядь. Рекурсия — она, конечно, мощная штука, но как слесарь-сантехник дядя Ваня: может и трубу прочистить, а может и всю квартиру затопить. Используй с умом, а лучше — ищи более прямые пути.