Kopiowanie tablicy obiektów do innej tablicy w javascript

Jak mogę skopiować każdy element tablicy (gdzie elementy są obiektami), do innej tablicy, tak aby były całkowicie niezależne? Nie chcę, aby zmiana elementu w jednej tablicy miała wpływ na drugą.

Author: Eric Smekens, 2013-04-26

7 answers

Jeśli tablica docelowa jeszcze nie istnieje...

...możesz użyć slice() lub concat(). slice() jest prawdopodobnie bardziej idiomatyczne( zobaczysz również slice(0), ale domyślną wartością jest 0, więc...):

var destinationArray = sourceArray.slice(); // Probably more idiomatic
// or
var destinationArray = sourceArray.concat();
W przeciwieństwie do ES2015 (inaczej ES6), istnieje również Array.from, która tworzy nową tablicę z dowolnej rzeczy podobnej do tablicy (włączając w to rzeczywistą tablicę):
var destinationArray = Array.from(sourceArray);

(Array.from może być shimmed/polyfilled dla starszych silników JavaScript.)

Również od ES2015 można używać notacji rozproszonej i tablicy literalna z dowolną iterowalną (w tym rzeczywistą tablicą):

var destinationArray = [...sourceArray];

Następnie obie tablice będą miały tę samą zawartość. Zmiana jednej tablicy nie zmieni drugiej. Oczywiście, jeśli wpis tablicy jest obiektem, wpis dla tego obiektu w obu tablicach będzie wskazywał na ten sam obiekt; nie jest to Kopia "głęboka".

Jeśli istnieje tablica docelowa...

...i chcesz dodać do niego zawartość tablicy źródłowej, możesz użyć push:

destinationArray.push.apply(destinationArray, sourceArray);

To działa przez wywołanie push w tablicy docelowej za pomocą apply funkcji JavaScript, która pozwala określić argumenty wywołania funkcji jako tablicę. push wypchnie tyle elementów, ile ma argumentów, więc kończy się kopiowaniem elementów z tablicy źródłowej do tablicy docelowej.

W ES2015 i nowszych, możesz zrobić to czystsze z notacją rozprzestrzeniania(...):

destinationArray.push(...sourceArray);

Zauważ, że w obu przypadkach wywołanie jest ograniczone przez maksymalny numer silnika JavaScript argumentów funkcji (w chwili pisania tego tekstu jest to przynajmniej w tysiącach dla wszystkich głównych silników [a nie w setkach tysięcy, przynajmniej nie dla Chrome ' a V8]).

Oto wersja ES5:

var source1, dest1, source2, dest2;

snippet.log("If dest doesn't exist yet:");
source1 = [1, 2, 3, 4];
dest1 = source1.slice(0);
snippet.log("[before change] source1 = " + source1.join(", "));
snippet.log("[before change] dest1 = " + dest1.join(", "));
source1[2] = "three";
dest1[3] = "four";
snippet.log("[after change] source1 = " + source1.join(", "));
snippet.log("[after change] dest1 = " + dest1.join(", "));

snippet.log("If dest already exists and we're just appending:");
source2 = [1, 2, 3, 4];
dest2 = ['a', 'b', 'c', 'd'];
snippet.log("[before append] source2 = " + source2.join(", "));
snippet.log("[before append] dest2 = " + dest2.join(", "));
dest2.push.apply(dest2, source2);
snippet.log("[before change] source2 = " + source2.join(", "));
snippet.log("[before change] dest2 = " + dest2.join(", "));
source2[2] = "three";
dest2[7] = "four";
snippet.log("[after change] source2 = " + source2.join(", "));
snippet.log("[after change] dest2 = " + dest2.join(", "));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
 72
Author: T.J. Crowder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-03 10:34:35

Łatwy sposób na to działa jest za pomocą:

var cloneArray = JSON.parse(JSON.stringify(originalArray));

Mam problemy z uzyskaniem arr.concat() lub arr.splice(0), aby dać głęboką kopię. Powyższy fragment działa idealnie.

 18
Author: jsbisht,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-12 16:40:08
var clonedArray = array.concat();
 3
Author: Ilya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-26 09:27:29

Świetnym sposobem na klonowanie tablicy jest użycie tablicy literal i operatora spreadu. Jest to możliwe dzięki ES2015 .

let objArray = [{name:'first'}, {name:'second'}, {name:'third'}, {name:'fourth'}];

let clonedArr = [...objArray];

console.log(clonedArr) // [Object, Object, Object, Object]

Tę opcję kopiowania można znaleźć w dokumentacji MDN dla operatorów rozproszonych https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Copy_an_array

Jest to również najlepsza praktyka Airbnb. https://github.com/airbnb/javascript#es6-array-spreads

Notatka: zazwyczaj operatory rozproszone w ES2015 sięgają jednego poziomu głęboko podczas kopiowania tablicy. Dlatego nie nadają się do kopiowania tablic wielowymiarowych.

 2
Author: MauricioLeal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-27 21:20:34

Jeśli chcesz zachować odniesienie:

Array.prototype.push.apply(destinationArray, sourceArray);

 1
Author: Veikko Karsikko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-20 18:02:24

Są dwie ważne uwagi.

  1. używanie array.concat() nie działa przy użyciu Angular 1.4.4 i jQuery 3.2.1 (to moje środowisko).
  2. array.slice(0) jest obiektem. Więc jeśli zrobisz coś w rodzaju newArray1 = oldArray.slice(0); newArray2 = oldArray.slice(0), dwie nowe tablice będą odwoływać się do tylko 1 tablicy, a zmiana jednej wpłynie na drugą.

Alternatywnie, użycie newArray1 = JSON.parse(JSON.stringify(old array)) spowoduje tylko skopiowanie wartości, w ten sposób utworzy za każdym razem nową tablicę.

 1
Author: Tran Vu Dang Khoa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-22 10:21:26

Sugeruję użycie concat() jeśli używasz nodeJS. We wszystkich innych przypadkach stwierdziłem, że slice(0) działa dobrze.

 0
Author: bean5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-11 07:34:02