← Назад к вопросам

Как скопировать массив?

2.0 Middle🔥 133 комментариев
#JavaScript Core

Комментарии (3)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как скопировать массив в JavaScript

Копирование массива — фундаментальная задача, и в JavaScript существует несколько методов, каждый со своей спецификой и областями применения. Важно понимать разницу между поверхностным (shallow) и глубоким (deep) копированием.

Поверхностное копирование

Поверхностное копирование создает новый массив, но элементы (особенно объекты или другие массивы) остаются ссылками на оригинальные. Методы:

  1. С использованием spread operator (...) — современный и рекомендуемый способ.
const original = [1, 2, 3, { name: 'Alice' }];
const copy = [...original];
  1. С помощью Array.from() — полезен для преобразования итерабельных объектов.
const original = [5, 6, 7];
const copy = Array.from(original);
  1. Метод slice() — классический подход без аргументов.
const original = [10, 20, 30];
const copy = original.slice();
  1. concat() с пустым массивом — менее распространенный, но рабочий вариант.
const copy = original.concat();

Проблема поверхностного копирования: изменяемые элементы (объекты) в копии влияют на оригинал.

copy[3].name = 'Bob';
console.log(original[3].name); // 'Bob' — оригинал тоже изменен!

Глубокое копирование

Глубокое копирование полностью дублирует массив и все его вложенные структуры, создавая независимую копию. Методы:

  1. JSON.parse() и JSON.stringify() — простой, но ограниченный способ. Не работает с функциями, undefined, Symbol, циклическими ссылкими.
const deepOriginal = [1, { nested: [2, 3] }];
const deepCopy = JSON.parse(JSON.stringify(deepOriginal));
  1. Рекурсивная функция — универсальный подход для любой глубины.
function deepClone(arr) {
    const result = [];
    for (let item of arr) {
        if (Array.isArray(item)) {
            result.push(deepClone(item));
        } else if (item && typeof item === 'object') {
            result.push(deepClone(Object.values(item)));
        } else {
            result.push(item);
        }
    }
    return result;
}
  1. С использованием сторонних библиотек — например, lodash с методом _.cloneDeep().
import _ from 'lodash';
const deepCopy = _.cloneDeep(original);
  1. Нативные APIstructuredClone(), появившийся в современных браузерах. Поддерживает многие типы данных, включая циклические ссылки.
const deepCopy = structuredClone(original);

Выбор метода в зависимости от контекста

  • Для простых массивов (числа, строки) — используйте spread operator или slice().
  • При наличии объектов внутри — если нужна независимость, требуется глубокое копирование.
  • В production-коде — для глубокого копирования предпочтительны structuredClone() или библиотеки (lodash), так как они надежнее и поддерживают edge cases.

Заключение

Копирование массива не является тривиальной операцией в JavaScript из-за ссылочной модели данных. Ключевой вопрос при выборе метода: насколько глубоко нужно копировать? Для иммутабельных данных подходят поверхностные методы, для сложных структур — глубокие. Понимание этих различий предотвращает множество ошибок, связанных с неожиданным изменением состояния.

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отличный вопрос! Копирование массивов в JavaScript — фундаментальная тема, которая проверяет понимание различий между примитивами и ссылками (reference types), а также знакомство с современным синтаксисом ES6+.

Ключевое понимание: простым присваиванием = массив не копируется. Вы создаёте новую переменную, которая ссылается на тот же самый массив в памяти.

const original = [1, 2, [3, 4]];
const badCopy = original; // Это НЕ копия!

badCopy.push(5);
console.log(original); // [1, 2, [3, 4], 5] - оригинал тоже изменился!

Существует два основных типа копирования: поверхностное (shallow) и глубокое (deep). Выбор метода зависит от структуры данных и требуемого результата.

Поверхностное копирование (Shallow Copy)

Создаётся новый массив, но если элементы сами являются объектами или массивами, копируются ссылки на них, а не сами вложенные структуры.

1. Spread оператор (...) (ES6+)

Современный, лаконичный и самый популярный способ.

const original = [1, 2, { a: 3 }];
const shallowCopy = [...original];

shallowCopy.push(4);
console.log(original); // [1, 2, { a: 3 }] - оригинальный массив не изменился

shallowCopy[2].a = 99;
console.log(original[2].a); // 99! Вложенный объект изменён в обоих массивах.

2. Array.from()

Функциональный подход, полезен также для преобразования массивоподобных объектов (например, NodeList).

const shallowCopy = Array.from(original);

3. slice() без аргументов

Классический метод, работающий во всех браузерах.

const shallowCopy = original.slice();

4. concat() с пустым массивом

Ещё один "старый" метод, идентичный по действию slice().

const shallowCopy = [].concat(original);

5. Object.values() или Object.entries() (для объектов-массивов)

Если нужно скопировать массив, представленный в виде объекта с числовыми ключами.

const arrayLike = { 0: 'a', 1: 'b', length: 2 };
const realArray = Object.values(arrayLike); // ['a', 'b']

Глубокое копирование (Deep Copy)

Создаётся полностью новый массив, рекурсивно копируются все вложенные массивы и объекты. Изменения в копии никак не затрагивают оригинал.

1. JSON.parse(JSON.stringify())

Самый известный "хак" для простых случаев. Имеет серьёзные ограничения:

  • Удаляет свойства со значением undefined.
  • Преобразует функции в null.
  • Не работает с циклическими ссылками.
  • Проблемы с особыми типами, например, Date (превратится в строку), Map, Set, RegExp.
const original = [1, { a: 2 }, new Date()];
const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy[1].a = 100;
console.log(original[1].a); // 2 - оригинальный объект не изменился
console.log(deepCopy[2] instanceof Date); // false! Это уже строка.

2. Рекурсивная функция

Напишем свою функцию, которая обходит все уровни вложенности.

function deepCloneArray(arr) {
    const result = [];
    for (const item of arr) {
        if (Array.isArray(item)) {
            result.push(deepCloneArray(item));
        } else if (item && typeof item === 'object') {
            result.push(deepCloneObject(item)); // Нужна аналогичная функция для объектов
        } else {
            result.push(item);
        }
    }
    return result;
}

3. Использование специальных библиотек

Наиболее надёжный способ для сложных структур.

  • lodash.cloneDeep — "золотой стандарт".
  • structuredClone() (современный нативный API)

Современный нативный метод: structuredClone()

В современных браузерах и Node.js (с v17) появился встроенный глобальный метод для глубокого копирования сложных объектов, включая циклические ссылки и многие встроенные типы.

const original = [1, { a: 2 }, new Date(), new Map([['key', 'value']])];
const deepCopy = structuredClone(original);

console.log(deepCopy[2] instanceof Date); // true! Дата сохранила тип.
console.log(deepCopy[3] instanceof Map); // true!

Сводная таблица выбора метода:

МетодТип копииПлюсыМинусы
[...arr] / slice()ПоверхностнаяБыстро, просто, современноНе копирует вложенные объекты
Object.assign([], arr)ПоверхностнаяМенее читаем, чем spread
JSON.parse/stringifyГлубокаяПросто для JSON-безопасных данныхТеряет функции, даты и special types
structuredClone()ГлубокаяНативно, быстро, обрабатывает сложные типыНе поддерживается в очень старых средах
lodash.cloneDeepГлубокаяМаксимальная надёжность и гибкостьТребует подключения сторонней библиотеки

Вывод и рекомендации

  • Для простых массивов (без вложенных объектов/массивов) или когда вам нужна именно поверхностная копия — используйте spread оператор [...arr] или arr.slice().
  • Для глубокого копирования в современном коде предпочитайте structuredClone(), если поддерживаемые версии браузеров/Node.js позволяют.
  • В legacy-проектах или для копирования структур с функциями, циклическими ссылками или специальными типами — используйте проверенную временем библиотеку lodash.cloneDeep.
  • Избегайте JSON.parse(JSON.stringify()) для любых данных, кроме простых сериализуемых JSON-структур, так как этот метод чреват тонкими и трудноуловимыми багами.

Понимание этих нюансов критически важно для предотвращения мутаций состояния в React, Vue, управлении состоянием в Redux и написания чистого, предсказуемого кода в целом.

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Копирование массивов в JavaScript: глубокое погружение

Копирование массива — фундаментальная операция, которая часто становится источником ошибок у начинающих разработчиков. В JavaScript массивы являются объектами, и при простом присваивании создаётся ссылка на тот же массив, а не независимая копия. Это приводит к неожиданным мутациям данных.

Поверхностное копирование

Поверхностное копирование создаёт новый массив с теми же элементами, но вложенные объекты или массивы остаются общими. Основные методы:

1. Оператор spread (ES6+) Современный и наиболее читаемый способ:

const original = [1, 2, 3, {name: 'test'}];
const copy = [...original];

2. Метод slice() Классический подход, работающий во всех браузерах:

const copy = original.slice();

3. Array.from() Полезен для преобразования массивоподобных объектов:

const copy = Array.from(original);

4. Метод concat() Создаёт новый массив путём объединения:

const copy = [].concat(original);

5. JSON методы (ограниченное применение)

const copy = JSON.parse(JSON.stringify(original));

⚠️ Важно: Этот метод теряет функции, undefined, Symbol и циклические ссылки.

Глубокое копирование

Когда массив содержит вложенные объекты или массивы, необходимо глубокое копирование:

1. Рекурсивная функция:

function deepCopy(arr) {
  const result = [];
  for (const item of arr) {
    if (Array.isArray(item)) {
      result.push(deepCopy(item));
    } else if (item && typeof item === 'object') {
      result.push(deepCopyObject(item));
    } else {
      result.push(item);
    }
  }
  return result;
}

2. Использование structuredClone (современный API):

const deeplyCopied = structuredClone(originalArray);

Этот метод поддерживается современными браузерами и корректно обрабатывает большинство типов данных.

3. Библиотечные решения:

  • Lodash: _.cloneDeep(array)
  • jQuery: $.extend(true, [], array)

Сравнение методов в таблице

МетодГлубинаСкоростьОсобенности
[...arr]ПоверхностнаяВысокаяСовременный синтаксис
slice()ПоверхностнаяВысокаяПоддержка старых браузеров
structuredClone()ГлубокаяСредняяСовременный стандарт
JSON методыГлубокаяНизкаяТеряет сложные типы

Практический пример и подводные камни

Рассмотрим классическую ошибку:

const users = [{id: 1, name: 'Alex'}, {id: 2, name: 'Maria'}];
const usersCopy = [...users];

usersCopy[0].name = 'Changed'; // Мутирует ОРИГИНАЛЬНЫЙ массив!
console.log(users[0].name); // 'Changed' - неожиданно!

Правильное глубокое копирование для этого случая:

const safeCopy = users.map(user => ({...user}));

Производительность и рекомендации

  • Для простых массивов используйте spread оператор или slice()
  • Для глубокого копирования предпочитайте structuredClone там, где он поддерживается
  • Избегайте JSON методов для данных со сложной структурой
  • При работе с большими массивами учитывайте производительность глубокого копирования

Ключевой принцип: всегда анализируйте структуру данных перед копированием. Если есть сомнения — делайте глубокое копирование, но помните о компромиссе производительности. В современных приложениях часто используют иммутабельные обновления, где создание новых массивов вместо мутации исходных становится стандартной практикой.

Как скопировать массив? | PrepBro