Как сделать копию массива javascript
У нас есть массив строк arr . Нужно получить отсортированную копию, но оставить arr неизменённым.
Создайте функцию copySorted(arr) , которая будет возвращать такую копию.
let arr = ["HTML", "JavaScript", "CSS"]; let sorted = copySorted(arr); alert( sorted ); // CSS, HTML, JavaScript alert( arr ); // HTML, JavaScript, CSS (без изменений)
Для копирования массива используем slice() и тут же – сортировку:
function copySorted(arr) < return arr.slice().sort(); >let arr = ["HTML", "JavaScript", "CSS"]; let sorted = copySorted(arr); alert( sorted ); alert( arr );
Скопировать значение массива, а не ссылку на него
Здравствуйте! Скажите, а как можно скопировать в JavaScript массив так, чтобы, при изменении копии, оригинал не менялся? Например:
a = [0, 1, 2, 3] b = clone(a) b[0] = 10 a[0] == 0 // => true
Можно ли реализовать такой метод clone ?
Отслеживать
задан 1 авг 2016 в 21:10
1,536 1 1 золотой знак 11 11 серебряных знаков 26 26 бронзовых знаков
6 ответов 6
Сортировка: Сброс на вариант по умолчанию
var a = [0, 1, 2, 3] var b = a.slice(0); b[0] = 10; console.log('a: ' + a); console.log('b: ' + b);
slice — возвращает поверхностную копию части массива в новый объект массива.
В данном случае с начала и до конца
Технически slice — наибыстрый путь, ОДНАКО это будет даже еще быстрее если добавить 0 — как начало «отрезания»
myArray.slice(0);
myArray.slice();
. так говорят языки %)
Отслеживать
ответ дан 1 авг 2016 в 21:16
Алексей Шиманский Алексей Шиманский
71.2k 12 12 золотых знаков 91 91 серебряный знак 180 180 бронзовых знаков
Скажите, а как сделать так: a = [0, 1, 2, 3] change(a) a == [1, 2] // => true a = [3, 2, 1] b = какой_то_метод(a) change(b) b == [2, 1] // => true a == [3, 2, 1] // => true
1 авг 2016 в 22:08
Действительно быстрее 🙂
1 авг 2016 в 23:26
Замер производительности
В хроме slice(0) действительно немного быстрее, чем просто slice() и в 2 раза быстрее, чем concat . А вот Array.from даже concat у проигрывает в 10 раз — 3 секунды на миллион итераций о_О.
А вот Edge так не считает — там concat самый быстрый. А Array.from по-прежнему в 10 (с хвостиком) раз медленнее concat а — 1.4 секунды.
При запуске сниппета браузер повиснет на несколько секунд — это нормально.
function test(f) < var a = [0, 1, 2, 3]; var t = performance.now(); f(a); t = performance.now() - t; console.log((""+f).match(/var b = .*$/m)[0] + " // " + t.toFixed(3) + " ms"); >test(function testSlice(a) < for (var q=0; q>); test(function testSlice0(a) < for (var q=0; q>); test(function testConcat(a) < for (var q=0; q>); test(function testFrom(a) < for (var q=0; q>); test(function testAssign(a) < // Так делать не надо, просто для сравнения for (var q=0; q>); test(function testDesruct(a) < for (var q=0; q>);
Создать независимую копию JavaScript массива :: Хранитель заметок
В JavaScript все присваивания объектов реализуются через передачу ссылок на них.
var oldArray = ["a", "b", "c"]; var newArray = oldArray;
Хоть мы и получили две разные переменные, но тем не менее они обе ссылаются на один и тот же объект массива. Если сейчас в одном массиве произвести какие-либо манипуляции с элементами, то аналогичные изменения можно будет увидеть и в другом.
Если вы хотите сделать независимую копию массива, то нужно использовать метод slice без аргументов.
var oldArray = ["a", "b", "c"]; var newArray = oldArray.slice();
Массивы oldArray и newArray будут состоять из одних и тех же элементов, но фактически это будут разные объекты.
Важно запомнить, что если массив состоит из сущностей Array или Object, то они по прежнему будут ссылаться на родительские объекты.
Ещё заметки со схожей тематикой
- Разная композиция функций
- Размер объекта в памяти
- Получение текущего состояние коллекции MongoDB в виде набора обновлений
Категории
Коментарии к заметке
Alexander , 07 июл 2011
slice реально очень хорошо помагает если надо скопировать массива. При этом, если измениь первый массив, то второй останется без изменений.
Дима , 08 окт 2015
Спасибо 🙂 Помогло
Елизарий , 18 апр 2016
Спасибо, искал долго, было много всего не по теме, а у вас сразу за пол странички все объяснили. Спасибо большое!
Илья , 15 сен 2016
Спасибо огромное, очень помогло с решением одной проблемы!!
Daddar , 12 окт 2016
атлант , 06 дек 2016
хорошо , ну а как все таки быть если в массиве сущности Обекты?
Владимир Кузнецов , 07 дек 2016
Атлант, тогда у этой задачи нет универсального решения. Объекты можно «клонировать» с помощью метода Object.assign() (описание Object.assign() на MDN).
var target = Object.assign(<>, source);
Но у этого метода как и slice() та же проблема — копируются только ссылки на вложенные объекты и массивы. Чтобы сделать глубокую копию всех данных, вам нужно рекурсивно вызывать соответствующие методы клонирования. В некоторых JS-библиотеках эти алгоритмы уже реализованы. Можете воспользоваться cloneDeep из библиотеки Lodash. А универсального решения задачи тут нет из-за того, что в ваших массивах и объектах могут храниться такие значения, для которых сложно или даже невозможно создать независимую копию, например, функции, DOM-узлы или объекты WeakMap.
arg , 24 авг 2017
Илья , 22 сен 2017
Способ, который работает и в случае, когда в массиве есть массивы или объекты:
var newArray = JSON.parse(JSON.stringify(oldArray))
Владимир Кузнецов , 22 сен 2017
Способ работающий, но очень медленный. Я бы не стал его использовать в проектах.
Илья , 26 мар 2018
Чуть мозг не поломал, пока не понял, что ссылки на объекты у скопированного массива действительно остаются прежними, спасибо за этот комментарий.
© 2009–2023 Владимир Кузнецов.
Все права защищены и принадлежат их владельцам.
Копирование материалов данного блога допускается только с разрешения автора.
Простое клонирование/копирование массива в JavaScript
Чтобы клонировать/копировать содержимое массива, все, что вам нужно сделать, это вызвать метод slice, передав 0 в качестве первого аргумента:
var clone = myArray.slice(0);
Код выше создает копию исходного массива; имейте в виду, если в вашем массиве существуют объекты — они хранятся как ссылки; т.е. код выше не делает “deep” клонирование содержимого массива.
Чтобы добавить копирование, как нативный метод к массивам, вы могли бы сделать что-то вроде этого:
Array.prototype.clone = function () < return this.slice(0); >;
Давайте напишем рекурсивную функцию, чтобы копировать массив, который потенциально может иметь вложенные объекты или массивы:
function arrayClone (arr) < var i, copy; if (Array.isArray(arr)) < copy = arr.slice(0); for (i = 0; i < copy.length; i++) < copy[i] = arrayClone(copy[i]); >return copy; > else if (typeof arr === 'object') < throw 'Cannot clone array containing an object!'; >else < return arr; >>
Если вы используете Underscore – можете сделать это еще короче:
function arrayClone (arr) < if (_.isArray(arr)) < return _.map(arr, arrayClone); >else if (typeof arr === 'object') < throw 'Cannot clone array containing an object!'; >else < return arr; >>
С версии ECMAScript 2015 был введен метод Object.assign(), с его помощью глубокое клонирование можно реализовать еще проще:
var clone = Object.assign([], myArray);
Заключение
Если вам нужно глубокое копирование произвольно-вложенных объектов и/или массивов, крошечный node-clone прекрасно с этим справиться. Он будет правильно обрабатывать даже копирование объектов с циклическими ссылками!
Источники
- Clone Arrays with JavaScript
- How to Clone a (Nested) Array in Javascript
