33 Вопрос: Копировать массив по значению

вопрос создан в Tue, Oct 2, 2018 12:00 AM

При копировании массива в JavaScript в другой массив:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

Я понял, что arr2 ссылается на тот же массив, что и arr1, а не на новый независимый массив. Как я могу скопировать массив, чтобы получить два независимых массива?

    
1567
  1. Похоже, что в настоящее время в Chrome 53 и Firefox 48 мы имеем отличную производительность для операций slice и splice, а новый оператор распространения и Array.from имеют гораздо более медленную реализацию. Посмотрите на perfjs.fnfo
    2016-09-16 13: 32: 29Z
  2. jsben.ch/#/wQ9RU < = этот тест дает обзор различных способов копирования массива
    2016-10-24 18: 47: 07Z
  3. 2017-05-25 17: 08: 21Z
  4. Для этого массива (который содержит примитивные строки) вы можете использовать var arr2 = arr1.splice(); для глубокого копирования, но этот метод не будет работать, если элементы в вашем массиве содержат литеральные структуры ( т.е. [] или {}) или объекты-прототипы (т.е. function () {}, new и т. д.). Смотрите мой ответ ниже для дальнейших решений.
    2017-08-27 22: 37: 29Z
  5. Это 2017 год, поэтому вы можете рассмотреть возможность использования функций ES6: let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    2017-09-22 08: 30: 36Z
30 ответов                              30                         

Используйте это:

var newArray = oldArray.slice();

По сути, slice() Операция клонирует массив и возвращает ссылку на новый массив.

Также обратите внимание, что:

Для ссылок, строк и чисел (а не фактического объекта) slice() копирует ссылки на объекты в новый массив. И исходный, и новый массивы ссылаются на один и тот же объект. Если ссылочный объект изменяется, изменения видны как новому, так и исходному массивам.

Примитивы, такие как строки и числа, являются неизменяемыми, поэтому изменения строки или числа невозможны.

    
2492
2019-06-06 06: 11: 47Z
  1. Что касается производительности, следующие тесты jsPerf на самом деле показывают, что var arr2 = arr1.slice () работает так же быстро, как var arr2 = arr1.concat (); JSPerf: jsperf.com/copy-array-slice-vs-concat/5 и jsperf.com/copy-simple-array . Результат jsperf.com/array-copy/5 своего рода удивил меня до такой степени, что я мне интересно, если тестовый код действителен.
    2012-12-19 18: 46: 32Z
  2. Несмотря на то, что он уже получил массу голосов, он заслуживает еще одногоИспользуйте его правильно описывает ссылки в JS, что, к сожалению, довольно редко.
    2014-01-20 16: 29: 15Z
  3. @ GáborImre вы бы добавили целую библиотеку просто для удобства чтения? В самом деле? Я бы просто добавил комментарий, если бы меня беспокоило удобочитаемость. Смотрите: var newArray = oldArray.slice (); //клонировать oldArray в newArray
    2016-02-08 19: 47: 23Z
  4. @ GáborImre Конечно, я понял. Но ответить на конкретную инженерную проблему, включив целую библиотеку, на мой взгляд, не полезно, это раздувание дизайна. Я вижу, что разработчики делают это много, и затем вы получаете проект, который включает в себя всю инфраструктуру вместо того, чтобы писать одну функцию. Только мой М.О., хотя.
    2016-02-09 19: 48: 13Z
  5. Извлеченный урок: не путайте .slice() с .splice(), что дает пустой массив. Большая разница.
    2018-02-28 06: 20: 32Z

В Javascript методы глубокого копирования зависят от элементов в массиве. Давайте начнем там.

Три типа элементов

Элементами могут быть: литеральные значения, литеральные структуры или прототипы.

// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';

// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};

// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); # or "new function () {}"

Из этих элементов мы можем создать три типа массивов.

// 1) Array of literal-values (boolean, number, string) 
const type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
const type2 = [[], {}];

// 3) Array of prototype-objects (function)
const type3 = [function () {}, function () {}];

Методы глубокого копирования зависят от трех типов массивов

На основе типов элементов в массиве мы можем использовать различные методы для глубокого копирования.

 Техника глубокого копирования Javascript по типам элементов

  • Массив литеральных значений (type1)
    Методы [...myArray], myArray.splice(0), myArray.slice() и myArray.concat() могут использоваться для глубокого копирования массивов только с литеральными значениями (логическими, числовыми и строковыми); где оператор Spread [...myArray] имеет наилучшую производительность ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ). р>

  • Массив литеральных значений (тип1) и литеральных структур (тип2)
    Метод JSON.parse(JSON.stringify(myArray)) можно использовать для глубокого копирования литеральных значений (логические, число, строка) и литеральных структур (массив, объект), но не объектов-прототипов.

  • Все массивы (тип1, тип2, тип3)
    Метод jQuery $.extend(myArray) может использоваться для глубокого копирования всех типов массивов. Такие библиотеки, как Underscore и Lo-dash предлагают аналогичные функции глубокого копирования для jQuery $.extend(), но при этом имеют более низкую производительность. Более удивительно, что $.extend() имеет более высокую производительность, чем метод JSON.parse(JSON.stringify(myArray)) http://jsperf.com/js-deep- копия /15 .
    И для тех разработчиков, которые избегают сторонних библиотек (таких как jQuery), вы можете использовать следующую пользовательскую функцию; которая имеет более высокую производительность, чем $.extend, и выполняет глубокое копирование всех массивов.

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

Итак, чтобы ответить на вопрос ...

Вопрос

var arr1 = ['a','b','c'];
var arr2 = arr1;
  

Я понял, что arr2 ссылается на тот же массив, что и arr1, а не на   новый, независимый массив. Как я могу скопировать массив, чтобы получить два   независимые массивы?

Ответ

Поскольку arr1 - это массив литеральных значений (логическое значение, число или строка), вы можете использовать любую методику глубокого копирования, описанную выше, где оператор распространения ... имеет наивысшую производительность.

// Highest performance for deep copying literal values
arr2 = [...arr1];

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.slice();
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above
    
463
2019-04-17 04: 33: 33Z
  1. Многие из тэти подходы не работают хорошо. Использование оператора присваивания означает, что вам необходимо переназначить исходное литеральное значение arr1. Это очень редко случается. Использование splice стирает arr1, так что это вообще не копия. При использовании JSON произойдет сбой, если какое-либо из значений в массиве будет иметь функции или иметь прототипы (например, Date).
    2014-09-18 19: 53: 45Z
  2. Использование соединения является частичным решением. Это потерпит неудачу при гораздо большем количестве случаев, чем JSON. Splice создает глубокую копию строк и чисел, когда перемещает значения - никогда не говорил, что возвращает копию.
    2014-10-03 06: 50: 58Z
  3. Почему splice (0)? Разве это не должно быть slice ()? Я думаю, что он не должен изменять исходный массив, что делает сплайсинг. @JamesMontagne
    2015-05-14 15: 29: 48Z
  4. Соединение
    создаст указатели на элементы в исходном массиве (мелкая копия). splice (0) выделит новую память (глубокое копирование) для элементов в массиве, которые являются числами или строками, и создаст указатели для всех других типов элементов (поверхностное копирование). Передав начальное значение, равное нулю, в метод-функцию сплайсинга, он не будет склеивать какие-либо элементы из исходного массива и, следовательно, не изменяет его.
    2015-05-21 09: 35: 47Z
  5. На самом деле, существует только один тип массива: массив «чего-то». Нет разницы между [0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]] и любым другим массивом.
    2016-04-07 09: 12: 16Z

Вы можете использовать массивы ... для копирования массивов.

const itemsCopy = [...items]; р>

Также, если вы хотите создать новый массив, в который входит существующий массив:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

Распределения массива теперь поддерживаются во всех основных браузерах . /a> но если вам нужна более старая поддержка, используйте машинопись или babel и скомпилируйте в ES5.

Подробнее о спредах р>     

178
2017-07-05 05: 57: 45Z

JQuery не требуется ... Пример работы

var arr2 = arr1.slice()

Это копирует массив из начальной позиции 0 до конца массива.

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

Если у вас есть массив ссылочных типов, скажем, типа Object. Массив будет скопирован, но оба массива будут содержать ссылки на одни и те же Object. Так что в этом случае может показаться, что массив копируется по ссылке, хотя массив фактически копируется.

    
150
2011-09-20 14: 24: 01Z
  1. Нет, это не будет глубокая копия.
    2014-10-14 22: 16: 02Z
  2. Попробуйте это; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
    2018-12-19 07: 11: 13Z
  3. В чем разница между этим ответом и принятым ответом?
    2019-04-13 14:04: 01Z

Альтернатива slice concat , который можно использовать двумя способами. Первый из них, возможно, более читабелен, так как предполагаемое поведение очень ясно:

var array2 = [].concat(array1);

Второй метод:

var array2 = array1.concat();

Коэн (в комментариях) отметил, что этот последний метод имеет более высокую производительность . р>

Это работает так, что метод concat создает новый массив, состоящий из элементов в объекте, для которого он вызывается, за которым следуют элементы любых массивов, передаваемых ему в качестве аргументов. Поэтому, когда аргументы не передаются, он просто копирует массив.

Ли Пенкман, также в комментариях, указывает, что если есть шанс array1 на undefined, вы можете вернуть пустой массив следующим образом:

var array2 = [].concat(array1 || []);

Или для второго метода:

var array2 = (array1 || []).concat();

Обратите внимание, что вы также можете сделать это с slice: var array2 = (array1 || []).slice();.

    
71
2015-05-11 19: 13: 53Z
  1. На самом деле вы также можете сделать: var array2 = array1.concat (); Это намного быстрее в отношении производительности. (JSPerf: jsperf.com/copy-simple-array и jsperf.com/copy-array-slice-vs-concat/5
    2012-12-19 18: 50: 00Z
  2. Стоит отметить, что если array1 не является массивом, то [].concat(array1) возвращает [array1], например. если его значение не определено, вы получите [undefined]. Иногда я делаю var array2 = [].concat(array1 || []);
    2014-08-01 08: 27: 10Z

Вот как я это сделал, попробовав множество подходов:

var newArray = JSON.parse(JSON.stringify(orgArray));

Это создаст новую глубокую копию, не связанную с первой (не мелкую копию).

Кроме того, это, очевидно, не будет клонировать события и функции, но хорошо, что вы можете сделать это в одну строку, и это может быть использовано для любого типа объекта (массивы, строки, числа, объекты ...)

    
52
2015-09-06 11: 40: 25Z
  1. Это лучший. Я давно использую тот же метод и думаю, что в рекурсивных циклах старой школы больше нет смысла
    2014-05-05 20: 28: 43Z
  2. Помните, что этот параметр плохо обрабатывает графоподобные структуры: происходит сбой при наличии циклов и не сохраняет общие ссылки.
    2014-06-28 23: 12: 07Z
  3. Это также не работает для таких вещей, как Date, или даже для всего, что имеет прототип. Кроме того, undefineds преобразуются в nulls.
    2014-09-18 19: 57: 08Z
  4. Достаточно ли храбрых, чтобы прокомментировать грубую неэффективность как процессора, так и памяти при сериализации в текст и последующем анализе до объекта?
    2014-12-09 23: 58: 55Z
  5. Это единственное решение, которое сработало. Использование slice () действительно фальшивое решение.
    2015-09-28 11: 52: 44Z

Некоторые из упомянутых методов хорошо работают при работе с простыми типами данных, такими как число или строка, но когда массив содержит другие объекты, эти методы не работают. Когда мы пытаемся передать любой объект из одного массива в другой, он передается как ссылка, а не как объект.

Добавьте следующий код в ваш файл JavaScript:

Object.prototype.clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (i in this) {
        if (i == 'clone') 
            continue;
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        } 
        else 
            newObj[i] = this[i]
    } return newObj;
};

И просто используйте

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

Это будет работать.

    
19
2015-09-06 11: 39: 02Z
  1. Я получаю эту ошибку, когда добавляю этот код на свою страницу 'Uncaught RangeError: Превышен максимальный размер стека вызовов'
    2013-01-21 17: 56: 46Z
  2. В каком браузере вы видели эту ошибку ??
    2013-04-10 12: 12: 20Z
  3. Мои извинения, эта ошибка возникает в chrome, если arr1 не объявлен. поэтому я скопировал код выше и получаю ошибку, однако, если я объявляю массив arr1, то я не получаю ошибку. Вы могли бы улучшить ответ, объявив arr1 чуть выше arr2, я вижу, что есть немало «нас», которые не осознавали, что мы должны объявить arr1 (отчасти потому, что когда я оценивал ваш ответ, я спешил и нужно что-то, что «просто работает»)
    2013-04-11 05: 01: 14Z
  4. .slice() по-прежнему работает нормально, даже если у вас есть объекты в вашем массиве: jsfiddle.net/edelman/k525g
    2013-05-30 19: 49: 35Z
  5. @ Джейсон, но объекты по-прежнему указывают на один и тот же объект, поэтому изменение одного изменит другой. jsfiddle.net/k525g/1
    2013-07-08 14: 39: 06Z

От ES2015,

var arr2 = [...arr1];
    
15
2015-12-24 07: 14: 04Z

Я лично считаю, что Array.from является более читабельным решением , Кстати, просто остерегайтесь его поддержки браузера.

//clone
let x = [1,2,3];
let y = Array.from(x);

//deep clone
let clone = arr => Array.from(arr,item => Array.isArray(item) ? clone(item) : item);
let x = [1,[],[[]]];
let y = clone(x);
    
14
2016-05-31 06: 37: 03Z
  1. Да, это очень удобно для чтения. Решение .slice() совершенно не интуитивно понятно. Спасибо за это.
    2016-07-27 14: 46: 14Z

Внимание!

Большинство ответов здесь подходит для особых случаев .

Если вас не интересуют глубокие /вложенные объекты и реквизиты ( ES6 ):

let clonedArray = [...array] р>

но если вы хотите сделать глубокое клонирование, используйте это вместо:

let cloneArray = JSON.parse(JSON.stringify(array)) р>

Для пользователей lodash:

let clonedArray = _.clone(array) документация

и р>

let clonedArray = _.cloneDeep(array) документация

    
13
2018-09-17 15: 31: 40Z

Если вы находитесь в среде ECMAScript 6 , используя Оператор распространения вы можете сделать это следующим образом: р>

р>

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>
    
11
2015-09-06 11: 52: 41Z

Добавляя к решению array.slice (); помните, что если у вас есть многомерный массив , подмассивы будут скопированы по ссылкам. Что вы можете сделать, так это зациклить и нарезать () каждый под-массив индивидуально

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

То же самое относится и к массиву объектов, они будут скопированы по ссылке, вы должны скопировать их вручную

    
9
2014-04-15 13: 40: 02Z
  1. Этот ответ заслуживает места в верхней части страницы! Я работал с многомерными вложенными массивами и не мог понять, почему внутренние массивы всегда копировались с помощью ref, а не val. Эта простая логика решила мою проблему. Я бы дал вам +100, если это возможно!
    2017-02-16 01: 33: 36Z

Как мы знаем в Javascript, массивы и объекты являются ссылками, но как мы можем сделать копию массива, не изменяя исходный массив позже, чем один?

Вот несколько способов сделать это:

Представьте, что в вашем коде есть этот массив:

var arr = [1, 2, 3, 4, 5];

1) Цикл по массиву в функции и возвращение нового массива, например так:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) Используя метод slice, slice предназначен для нарезки части массива, он будет нарезать некоторую часть вашего массива, не касаясь оригинала, в срезе, если не указать начало и конец массива, он будет разрезать весь массив и в основном сделать полную копию массива, так что мы можем легко сказать:

var arr2 = arr.slice(); // make a copy of the original array

3) Также контактный метод, это для слияния двух массивов, но мы можем просто указать один из массивов, и тогда это в основном сделает копию значений в новом контактируемом массиве:

var arr2 = arr.concat();

4) Также метод stringify и parse, не рекомендуется, но может быть простым способом скопировать массив и объекты:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Метод Array.from, который широко не поддерживается, перед использованием проверьте поддержку в различных браузерах:

const arr2 = Array.from(arr);

6) Способ ECMA6, также не полностью поддерживается, но babelJs может помочь вам, если вы хотите перенести:

const arr2 = [...arr];
    
6
2018-05-01 00: 20: 58Z

В моем конкретном случае мне нужно было убедиться, что массив остался нетронутым, так что это сработало для меня:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}
    
4
2015-10-29 23: 45: 26Z
  1. + 1 за то, что вы не добавили неясность в ваш код, вызвав функцию, которая делает то же самое, но менее очевидным способом. slice может быть более эффективным под капотом, но для всех, кто работает над кодом, это показывает ваше намерение. Кроме того, это упрощает оптимизацию позже, если вы хотите (например) фильтровать то, что копируете. обратите внимание, однако, что это не обрабатывает глубокое копирование, а те же внутренние объектыпередаются в новый массив, по ссылке. Это может быть то, что вы хотите сделать, а может и нет.
    2014-06-30 22: 45: 43Z

Сделать копию многомерного массива /объекта:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

Спасибо Джеймсу Падолси за эту функцию.

Источник: Здесь

    
4
2017-02-06 07: 13: 12Z

Дэн, не нужно использовать причудливые трюки. Все, что вам нужно сделать, это сделать копию arr1, выполнив это.

р>

var arr2 = new Array(arr1);

Теперь arr1 и arr2 - это две разные переменные массива, которые хранятся в отдельных стеках. Проверьте это на jsfiddle .

    
4
2018-05-18 15: 05: 09Z
  1. Это не копирует массив. Он создает массив с одним элементом, который ссылается на оригинал (т.е. var arr2 = [arr1];).
    2018-11-21 23: 25: 09Z

Когда мы хотим скопировать массив с помощью оператора присваивания (=), он не создает копию, а просто копирует указатель /ссылку на массив. Например:

р>

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

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

Способы копирования массива:

р>

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

Будьте осторожны, когда массивы или объекты вложены!

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

р>

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

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

Если вы хотите глубоко клонировать массив javascript, используйте JSON.parse в сочетании с JSON.stringify, например так:

р>

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

Производительность копирования:

Итак, какой из них мы выбираем для оптимальной производительности. Оказывается, что наиболее многословный метод, цикл for, имеет самую высокую производительность. Используйте цикл for для по-настоящему ресурсоемкого копирования (большой /много массивов).

После этого метод .slice() также имеет приличную производительность, а также менее многословен и более прост для реализации программистом. Я предлагаю использовать .slice() для ежедневного копирования массивов, которые не сильно нагружают процессор. Также избегайте использования JSON.parse(JSON.stringify(arr)) (много накладных расходов), если глубокий клон не требуется и производительность является проблемой.

Тест производительности исходного кода р>     

3
2018-08-09 22: 46: 58Z

Если ваш массив содержит элементы primiТип данных tive , например int, char или string и т. д. , затем вы можете использовать один из тех методов, который возвращает копию исходного массива, например .slice () или .map (). или оператор распространения (благодаря ES6).

new_array = old_array.slice()

или р>

new_array = old_array.map((elem) => elem)

или р>

const new_array = new Array(...old_array);

НО , если ваш массив содержит сложные элементы , такие как объекты (или массивы) или более вложенных объектов , то вам придется выполнить следующие действия: убедитесь, что вы делаете копию всех элементов с верхнего уровня до последнего уровня, иначе будет использована ссылка на внутренние объекты, и это означает, что изменение значений в object_elements в new_array все равно повлияет на old_array. Вы можете назвать этот метод копирования на каждом уровне как создание ГЛУБОКОЙ КОПИИ . из старого массива.

Для глубокого копирования вы можете использовать вышеупомянутые методы для примитивных типов данных на каждом уровне в зависимости от типа данных или использовать этот дорогостоящий метод (упомянутый ниже) для создания глубокого копирования. копировать без особой работы.

var new_array = JSON.parse(JSON.stringify(old_array));

Существует множество других методов, которые вы можете использовать в зависимости от ваших требований. Я упомянул только некоторые из них, чтобы дать общее представление о том, что происходит, когда мы пытаемся скопировать массив в другой по значению .

    
3
2018-09-26 13: 52: 41Z
  1. Большое спасибо, ваш ответ был единственным, кто работал для моего сценария,
    2019-06-19 03: 07: 40Z

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

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

В Google можно найти дополнительную информацию об неизменных значениях примитивов и ссылках на изменяемые объекты.

    
2
2015-09-06 11: 32: 58Z
  1. Вам не нужно явно копировать свойства объектов массива. См. Ответ Чтиви Малека.
    2014-06-04 14: 30: 16Z

Используя глубокое копирование jQuery, можно сделать следующее:

var arr2 = $.extend(true, [], arr1);
    
2
2017-01-12 19: 26: 26Z

Вы также можете использовать оператор распространения ES6 для копирования массива

var arr=[2,3,4,5];
var copyArr=[...arr];
    
2
2017-06-30 19: 16: 15Z

Вот еще несколько способов копирования:

р>

const array = [1,2,3,4];

const arrayCopy1 = Object.values(array);
const arrayCopy2 = Object.assign([], array);
const arrayCopy3 = array.map(i => i);
const arrayCopy4 = Array.of(...array );
    
2
2018-04-12 07: 00: 17Z

Быстрые примеры:

  1. Если элементы в массиве являются примитивными типами (строка, число и т. д.)

р>

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]
  1. Если элементы в массиве являются объектными литералами, другой массив ({}, [])

р>

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
  1. Решение для 2 : глубокое копирование от элемента к элементу

р>

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
arr2 = JSON.parse(JSON.stringify(arr1));
arr2.pop();	  // OK - don't affect arr1
arr2[0].x = 'z';  // OK - don't affect arr1
arr2[1][0] = 9;	  // OK - don't affect arr1

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
    
2
2018-09-11 13: 47: 21Z
let a = [1,2,3];

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

let b = Array.from(a); 

ИЛИ р>

let b = [...a];

ИЛИ р>

let b = new Array(...a); 

ИЛИ р>

let b = a.slice(); 

ИЛИ р>

let b = a.map(e => e);

Теперь, если я изменю,

a.push(5); 

Тогда a равно [1,2,3,5], но b по-прежнему [1,2,3], так как оно имеет другую ссылку.

Но я думаю, что во всех описанных выше методах Array.from лучше и сделан в основном для копирования массива.

    
2
2019-01-02 18: 03: 31Z
  1. какой из них самый быстрый?
    2019-06-07 02: 11: 45Z

Вот вариант:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */
    
1
2013-10-06 06: 36: 14Z
  1. неплохая идея, хотя я бы лучше использовал JSON stringify /parse вместо eval, и было бы неплохо проверить еще одно сравнение jsPerf, также обратите внимание на toSource не является стандартным и не будет работать в Chrome, например.
    2014-03-24 19: 23: 48Z

Есть недавно представленный Array.from, но, к сожалению, на момент написания этой статьи он поддерживается только в последних версиях Firefox (32 и выше). Его можно просто использовать следующим образом:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

Ссылка: Здесь р>

Или Array.prototype.map можно использовать с функцией идентификации:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

Ссылка: Здесь р>     

1
2017-02-06 07: 46: 48Z
  1. + 1 за упоминание Array.from, который теперь поддерживается во всех основных браузерах, кроме Internet Explorer ( source ). .
    2017-10-18 11: 16: 04Z

Это можно сделать следующим образом:
arr2 = arr1.map(x => Object.assign({}, x));

    
1
2018-05-31 11: 50: 15Z

Вы можете использовать ES6 с распространением Opeartor, это проще.

arr2 = [...arr1];

Существуют ограничения ... проверьте документы Синтаксис распространения @ mozilla

    
1
2018-06-27 09: 06: 09Z

Вот как вы можете это сделать для массива массивов примитивов переменной глубины:

// If a is array: 
//    then call cpArr(a) for each e;
//    else return a

const cpArr = a => Array.isArray(a) && a.map(e => cpArr(e)) || a;

let src = [[1,2,3], [4, ["five", "six", 7], true], 8, 9, false];
let dst = cpArr(src);

https://jsbin.com/xemazog/edit?js,console р>     

1
2018-12-13 11: 15: 55Z

Примитивные значения всегда передаются по его значению (копируются). Составные значения, однако, передаются по ссылке.

Так, как мы копируем этот arr?

let arr = [1,2,3,4,5];

Скопируйте массив в ES6

let arrCopy = [...arr]; 

Скопируйте массив в ES5

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

Почему `let arrCopy = arr` не передается по значению?

Передача одной переменной в другую по составным значениям, таким как объект /массив, ведет себя по-разному. Используя оператор asign для значений copand, мы передаем ссылку на объект. Вот почему значение обоих массивов изменяется при удалении /добавлении элементов arr.

Исключения:

arrCopy[1] = 'adding new value this way will unreference';

Когда вы присваиваете новое значение переменной, вы изменяете саму ссылку, и она не влияет на исходный объект /массив.

узнать больше

    
1
2018-12-31 01: 57: 21Z
источник размещен Вот
Другие вопросы