При копировании массива в JavaScript в другой массив:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
Я понял, что arr2
относится к тому же массиву arr1
, а не к новому, независимому массиву. Как я могу скопировать массив, чтобы получить два независимых массива?
javascript
arrays
Дэн
источник
источник
slice
иsplice
операции, а также новый оператор распространения иArray.from
значительно медленнее реализация. Посмотрите на perfjs.fnfovar arr2 = arr1.splice();
для глубокого копирования, но этот метод не будет работать, если элементы в вашем массиве содержат литеральные структуры (т.е.[]
или{}
) или объекты-прототипы (то естьfunction () {}
,new
и т. Д.). Смотрите мой ответ ниже для дальнейших решений.let arr2 = [...arr1];
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Ответы:
Использовать этот:
По сути,
slice()
операция клонирует массив и возвращает ссылку на новый массив.Также обратите внимание, что:
Для ссылок, строк и чисел (а не для реального объекта)
slice()
копирует ссылки на объекты в новый массив. И исходный, и новый массив ссылаются на один и тот же объект. Если ссылочный объект изменяется, изменения видны как новому, так и исходному массивам.Примитивы, такие как строки и числа, являются неизменными, поэтому изменения строки или числа невозможны.
источник
.slice()
с.splice()
, что дает пустой массив. Большая разница.В Javascript методы глубокого копирования зависят от элементов в массиве. Давайте начнем там.
Три типа элементов
Элементами могут быть: буквальные значения, буквенные структуры или прототипы.
Из этих элементов мы можем создать три типа массивов.
Методы глубокого копирования зависят от трех типов массивов
Основываясь на типах элементов в массиве, мы можем использовать различные методы для глубокого копирования.
Массив буквенных значений (type1) , , и методы могут быть использованы для глубоких копии массивов с буквенными значениями (булева, число и строка) только; где оператор Spread имеет лучшую производительность ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).
[...myArray]
myArray.splice(0)
myArray.slice()
myArray.concat()
[...myArray]
Массив литеральных значений (type1) и литеральных структур (type2)
Этот
JSON.parse(JSON.stringify(myArray))
метод может использоваться для глубокого копирования литеральных значений (логических, числовых, строковых) и литеральных структур (массив, объект), но не объектов-прототипов.Все массивы (type1, type2, type3) Техника
jQuery
$.extend(myArray)
может использоваться для глубокого копирования всех типов массивов. Такие библиотеки, как Underscore и Lo-dash, предлагают функции глубокого копирования, аналогичные jQuery$.extend()
, но имеют более низкую производительность. Более удивительно,$.extend()
имеет более высокую производительность, чемJSON.parse(JSON.stringify(myArray))
метод http://jsperf.com/js-deep-copy/15 .И для тех разработчиков, которые избегают сторонних библиотек (таких как jQuery), вы можете использовать следующую пользовательскую функцию; которая имеет более высокую производительность, чем $ .extend, и копирует все массивы.
Итак, чтобы ответить на вопрос ...
Вопрос
Ответ
Поскольку
arr1
это массив литеральных значений (логические, числовые или строковые), вы можете использовать любую методику глубокого копирования, рассмотренную выше, где оператор распространения...
имеет наибольшую производительность.источник
arr1
. Это очень редко, что это будет иметь место. Использованиеsplice
стираетarr1
, так что это не копия вообще. Использование неJSON
будет выполнено, если какое-либо из значений в массиве является Функцией или имеет прототипы (например, aDate
).[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]
любым другим массивом.Вы можете использовать массивы
...
для копирования массивов.const itemsCopy = [...items];
Также, если вы хотите создать новый массив с существующим, являющимся его частью:
Распространения массива теперь поддерживаются во всех основных браузерах, но если вам нужна более старая поддержка, используйте машинопись или babel и компилируйте в ES5.
Больше информации о спредах
источник
Нет необходимости jQuery ... Рабочий пример
Это копирует массив из начальной позиции
0
до конца массива.Важно отметить, что он будет работать как ожидается для примитивных типов (строка, число и т. Д.), А также объяснить ожидаемое поведение для ссылочных типов ...
Если у вас есть массив ссылочных типов, скажем, типа
Object
. Массив будет скопирован, но оба массива будут содержать ссылки на одинаковыеObject
. Таким образом, в этом случае может показаться, что массив копируется по ссылке, хотя массив фактически копируется.источник
var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
Альтернативой
slice
является тоconcat
, что можно использовать двумя способами. Первый из них, возможно, более читабелен, так как предполагаемое поведение очень ясно:Второй метод:
Коэн (в комментариях) отметил, что этот последний метод имеет лучшую производительность .
Это работает так, что
concat
метод создает новый массив, состоящий из элементов объекта, для которого он вызывается, и элементов любых массивов, передаваемых ему в качестве аргументов. Поэтому, когда аргументы не передаются, он просто копирует массив.Ли Penkman, а также в комментариях, указывает на то , что если есть шанс , что
array1
этоundefined
, вы можете вернуть пустой массив следующим образом :Или для второго метода:
Обратите внимание , что вы можете сделать это с помощью
slice
:var array2 = (array1 || []).slice();
.источник
[].concat(array1)
возвращается,[array1]
например, если он не определен, вы получите[undefined]
. Я иногда делаюvar array2 = [].concat(array1 || []);
Вот как я сделал это после попытки многих подходов:
Это создаст новую глубокую копию, не связанную с первой (не мелкую копию).
Также это, очевидно, не будет клонировать события и функции, но хорошо, что вы можете сделать это в одну строку, и это может быть использовано для любого типа объекта (массивы, строки, числа, объекты ...)
источник
Date
, или, действительно, для всего, что имеет прототип. Кроме того,undefined
s конвертируются вnull
s.Некоторые из упомянутых методов хорошо работают при работе с простыми типами данных, такими как число или строка, но когда массив содержит другие объекты, эти методы не работают. Когда мы пытаемся передать любой объект из одного массива в другой, он передается как ссылка, а не как объект.
Добавьте следующий код в ваш файл JavaScript:
И просто использовать
Это будет работать.
источник
.slice()
все еще работает нормально, даже если у вас есть объекты в вашем массиве: jsfiddle.net/edelman/k525gОт ES2015,
источник
Лично я считаю Array.from более читабельным решением. Кстати, просто остерегайтесь его поддержки браузера.
источник
.slice()
Решение полностью неинтуитивное. Спасибо за это.Важный!
Большинство ответов здесь работает для конкретных случаев .
Если вам не нужны глубокие / вложенные объекты и реквизит ( ES6 ):
let clonedArray = [...array]
но если вы хотите сделать глубокий клон, используйте вместо этого:
let cloneArray = JSON.parse(JSON.stringify(array))
Для пользователей lodash:
let clonedArray = _.clone(array)
документацияа также
let clonedArray = _.cloneDeep(array)
документацияисточник
Если вы находитесь в среде ECMAScript 6 , используя Spread Operator, вы можете сделать это следующим образом:
источник
Добавление к решению array.slice (); Имейте в виду, что если у вас есть многомерный массив, под-массивы будут скопированы по ссылкам. Что вы можете сделать, так это зациклить и нарезать () каждый под-массив отдельно
То же самое относится к массиву объектов, они будут скопированы по ссылке, вы должны скопировать их вручную
источник
Примитивные значения всегда передаются по его значению (копируются). Однако составные значения передаются по ссылке.
Так, как мы копируем этот arr?
Скопируйте массив в ES6
Скопируйте Массив в ES5
Почему `let arrCopy = arr` не передается по значению?
Передача одной переменной в другую по составным значениям, таким как объект / массив, ведет себя по-разному. Используя оператор asign для значений copand, мы передаем ссылку на объект. Вот почему значение обоих массивов изменяется при удалении / добавлении элементов arr.
Исключения:
Когда вы присваиваете новое значение переменной, вы изменяете саму ссылку, и это не влияет на исходный объект / массив.
читать далее
источник
Как мы знаем в массивах и объектах Javascript, это ссылки, но какими способами мы можем сделать копию массива, не изменяя исходный массив позже, чем один?
Вот несколько способов сделать это:
Представьте, что у нас есть этот массив в вашем коде:
1) Цикл по массиву в функции и возврат нового массива, например так:
2) Используя метод slice, slice предназначен для нарезки части массива, он будет нарезать некоторую часть вашего массива, не касаясь оригинала, в срезе, если не указать начало и конец массива, он будет нарезать весь массив массив и в основном сделать полную копию массива, поэтому мы можем легко сказать:
3) Также контактный метод, это для объединения двух массивов, но мы можем просто указать один из массивов, и тогда это в основном сделает копию значений в новом контактируемом массиве:
4) Также метод stringify и parse, не рекомендуется, но может быть простым способом скопировать Array и Objects:
5) Метод Array.from, это широко не поддерживается, перед использованием проверьте поддержку в разных браузерах:
6) Способ ECMA6, также не полностью поддерживается, но babelJs может помочь вам, если вы хотите перейти:
источник
Теперь вы можете выполнить любое из следующих действий, чтобы сделать копию массива.
ИЛИ
ИЛИ
ИЛИ
ИЛИ
Теперь, если я поменяю
Тогда a равно [1,2,3,5], но b по-прежнему [1,2,3], так как оно имеет другую ссылку.
Но я думаю, что во всех методах выше Array.from лучше и сделан в основном для копирования массива.
источник
Я бы лично предпочел такой способ:
источник
В моем конкретном случае мне нужно было убедиться, что массив остался нетронутым, так что это сработало для меня:
источник
Сделайте копию многомерного массива / объекта:
Спасибо Джеймсу Падолси за эту функцию.
Источник: Здесь
источник
Дэн, не нужно использовать причудливые трюки. Все, что вам нужно сделать, это сделать копию arr1, выполнив это.
Теперь
arr1
иarr2
две разные переменные массива хранятся в отдельных стеках. Проверьте это на jsfiddle .источник
var arr2 = [arr1];
).Когда мы хотим скопировать массив с помощью оператора присваивания (
=
), он не создает копию, а просто копирует указатель / ссылку на массив. Например:Часто, когда мы преобразуем данные, мы хотим сохранить исходную структуру данных (например, массив) нетронутой. Мы делаем это путем создания точной копии нашего массива, чтобы его можно было преобразовать, пока исходный остается неизменным.
Способы копирования массива:
Будьте осторожны, когда массивы или объекты вложены !:
Когда массивы вложены, значения копируются по ссылке. Вот пример того, как это может привести к проблемам:
Поэтому не используйте эти методы, когда в вашем массиве есть объекты или массивы, которые вы хотите скопировать. т.е. использовать эти методы только для массивов примитивов.
Если вы хотите глубокое клонирование массива javascript, используйте
JSON.parse
в сочетании сJSON.stringify
:Выполнение копирования:
Итак, какой из них мы выбираем для оптимальной производительности. Получается, что самый многословный метод
for
цикла имеет наибольшую производительность. Используйтеfor
цикл для действительно интенсивного копирования процессора (большой / много массивов).После этого
.slice()
метод также имеет приличную производительность, а также менее многословен и более прост для реализации программистом. Я предлагаю использовать.slice()
для повседневного копирования массивов, которые не сильно загружают процессор. Также избегайте использованияJSON.parse(JSON.stringify(arr))
(много накладных расходов), если глубокое клонирование не требуется и производительность является проблемой.Тест производительности источника
источник
Если ваш массив содержит элементы типа данных примитива, такие как int, char или string и т. Д. То вы можете использовать один из тех методов, который возвращает копию исходного массива, например .slice () или .map () или оператор распространения ( спасибо ES6).
или
или
НО, если ваш массив содержит сложные элементы, такие как объекты (или массивы) или несколько вложенных объектов , то вам необходимо убедиться, что вы делаете копию всех элементов с верхнего уровня до последнего уровня, а также ссылки на внутренний объекты будут использоваться, и это означает, что изменение значений в object_elements в new_array все равно повлияет на old_array. Вы можете вызвать этот метод копирования на каждом уровне, делая полную копию из old_array.
Для глубокого копирования вы можете использовать вышеупомянутые методы для примитивных типов данных на каждом уровне в зависимости от типа данных, или вы можете использовать этот дорогостоящий метод (упомянутый ниже) для создания глубокой копии без особой работы.
Есть много других методов, которые вы можете использовать в зависимости от ваших требований. Я упомянул только некоторые из них, чтобы дать общее представление о том, что происходит, когда мы пытаемся скопировать массив в другой по значению .
источник
Если вы хотите создать новую копию объекта или массива, вы должны явно скопировать свойства объекта или элементов массива, например:
Вы можете найти в Google дополнительную информацию об неизменных значениях примитивов и ссылках на изменяемые объекты.
источник
Используя глубокое копирование jQuery, можно сделать следующее:
источник
Вы также можете использовать оператор распространения ES6 для копирования массива
источник
Вот еще несколько способов копирования:
источник
Вы можете использовать ES6 с распространением Opeartor, это проще.
Существуют ограничения. Проверьте документы. Синтаксис распространения @ mozilla.
источник
Быстрые примеры:
источник
Вот вариант:
источник
toSource
не является стандартным и не будет работать, например, в Chrome.Это недавно появившаяся
Array.from
версия, но, к сожалению, на момент написания этой статьи она поддерживается только в последних версиях Firefox (32 и выше). Его можно просто использовать следующим образом:Ссылка: здесь
Или
Array.prototype.map
может использоваться с функцией идентификации:Ссылка: здесь
источник
Array.from
, которое теперь поддерживается во всех основных браузерах, кроме Internet Explorer ( источник ). ,Array.from
что данные будут видоизменяться, не обеспечивает глубокого копирования / глубокого клонирования.Для массива ES6, содержащего объекты
источник