Copy-array per waarde

Bij het kopiëren van een array in JavaScript naar een andere array:

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

Ik besefte dat arr2verwijst naar dezelfde array als arr1, in plaats van een nieuwe, onafhankelijke array. Hoe kan ik de array kopiëren om twee onafhankelijke arrays te krijgen?


1, Autoriteit 100%

Gebruik dit:

let oldArray = [1, 2, 3, 4, 5];
let newArray = oldArray.slice();
console.log({newArray});

2, Autoriteit 20%

In JavaScript zijn deep-copy-technieken afhankelijk van de elementen in een array. Laten we daar beginnen.

Drie soorten elementen

Elementen kunnen zijn: letterlijke waarden, letterlijke structuren of prototypen.

// 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 () {}`

Van deze elementen kunnen we drie soorten arrays maken.

// 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 () {}];

Deep Copy-technieken zijn afhankelijk van de drie array-typen

Op basis van de soorten elementen in de array kunnen we verschillende technieken gebruiken voor diepe kopie.

  • Selectie van letterlijke waarden (Type1)
    De [...myArray], myArray.splice(0), myArray.slice(), en myArray.concat()TECHNIEKEN KUNNEN WORDEN GEBRUIKT OM ALLEEN TE DEUKE COPY-arrays met letterlijke waarden (Boolean, nummer en string); Waar de spread-operator [...myArray]heeft de beste prestaties (https://measurethat.net/benchmarks/show/4281/0/spread-array-performance-vs-slice-splice-concat ).

  • Selectie van letterlijke waarden (Type1) en letterlijke structuren (Type2)
    De JSON.parse(JSON.stringify(myArray))Techniek kan worden gebruikt voor het diep kopiëren van letterlijke waarden (Boolean, nummer, string) en letterlijke structuren (array, object), maar geen prototype-objecten.

  • Alle arrays (Type1, Type2, Type3)
    De jQuery $.extend(myArray)techniek kan worden gebruikt om alle array-types diep te kopiëren. Bibliotheken zoals Underscoreen Lo-dashbieden vergelijkbare deep-copy-functies als jQuery$.extend(), maar hebben lagere uitvoering. Verrassenderwijs heeft $.extend()hogere prestaties dan de JSON.parse(JSON.stringify(myArray))techniek http://jsperf.com/js-deep-copy/15.
    En voor die ontwikkelaars die bibliotheken van derden (zoals jQuery) schuwen, kunt u de volgende aangepaste functie gebruiken; die hogere prestaties heeft dan $.extend, en alle arrays diep kopieert.

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;
}

Dus om de vraag te beantwoorden…

Vraag

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

Ik realiseerde me dat arr2 verwijst naar dezelfde array als arr1, in plaats van a
nieuwe, onafhankelijke array. Hoe kan ik de array kopiëren om er twee te krijgen?
onafhankelijke arrays?

Antwoord

Omdat arr1een array is van letterlijke waarden (boolean, getal of tekenreeks), kunt u elke hierboven besproken deep copy-techniek gebruiken, waarbij de spread-operator ...heeft de hoogste prestaties.

// 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

Antwoord 3, autoriteit 7%

U kunt array-spreads ...gebruiken om arrays te kopiëren.

const itemsCopy = [...items];

Ook als u een nieuwe array wilt maken waarbij de bestaande er deel van uitmaakt:

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

Array-spreads worden nu ondersteund in alle belangrijke browsersmaar als je oudere ondersteuning nodig hebt, gebruik dan typoscript of babel en compileer naar ES5.

Meer informatie over spreads


Antwoord 4, autoriteit 5%

Geen jQuery nodig… Werkvoorbeeld

var arr2 = arr1.slice()

Dit kopieert de array vanaf de startpositie 0tot het einde van de array.

Het is belangrijk op te merken dat het zal werken zoals verwacht voor primitieve typen (string, nummer, enz.), en om ook het verwachte gedrag voor referentietypen …

te verklaren

Als u een reeks referentietypen hebt, zegt u van Type Object. De array zal worden gekopieerd, maar beide arrays bevatten verwijzingen naar dezelfde ObjectS. Dus in dit geval lijkt het erop dat de array wordt gekopieerd door verwijzing, hoewel de array daadwerkelijk is gekopieerd.


Antwoord 5, autoriteit 2%

Dit is hoe ik het heb gedaan na vele benaderingen te hebben geprobeerd:

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

Hiermee wordt een nieuwe diepe kopie gemaakt die niet gerelateerd is aan de eerste (geen oppervlakkige kopie).

Dit zal natuurlijk ook geen gebeurtenissen en functies klonen, maar het goede is dat je het in één regel kunt doen, en het kan voor elk soort object worden gebruikt (arrays, strings, getallen, objecten …)


Antwoord 6

Persoonlijk denk ik dat Array.fromis een beter leesbare oplossing. Pas trouwens op voor de browserondersteuning.

// clone
let x = [1, 2, 3];
let y = Array.from(x);
console.log({y});
// deep clone
let clone = arr => Array.from(arr, item => Array.isArray(item) ? clone(item) : item);
x = [1, [], [[]]];
y = clone(x);
console.log({y});

Antwoord 7

Sommige van de genoemde methoden werken goed bij het werken met eenvoudige gegevenstypen zoals getallen of tekenreeksen, maar wanneer de array andere objecten bevat, mislukken deze methoden. Wanneer we een object van de ene array naar de andere proberen door te geven, wordt het doorgegeven als een referentie, niet het object.

Voeg de volgende code toe aan uw JavaScript-bestand:

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;
};

En gebruik gewoon

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

Het zal werken.


Antwoord 8

Vanaf ES2015,

var arr2 = [...arr1];

Antwoord 9

Belangrijk!

De meeste antwoorden hier werken voor bijzondere gevallen.

Als je niet geeft om diepe/geneste objecten en rekwisieten, gebruik dan (ES6):

let clonedArray = [...array]

maar als je een diepe kloon wilt doen, gebruik dan dit:

let cloneArray = JSON.parse(JSON.stringify(array))*

*functies worden niet bewaard (serialized) tijdens het gebruik van stringify, je krijgt resultaat zonder ze.


Voor lodash-gebruikers:

let clonedArray = _.clone(array)documentatie

en

let clonedArray = _.cloneDeep(array)Documentatie


10

Als u in een omgeving van ecmascript 6 , met behulp van de Spread-operator U zou het op deze manier kunnen doen:

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');
console.log(arr1)
console.log(arr2)
<script src="https://www.wzvang.com/snippet/ignore_this_file.js"></script>

11

Primitieve waarden worden altijd doorgegeven aan zijn waarde (gekopieerd). Verbindingswaarden worden echter door verwijzing doorgegeven.

Dus hoe kopiëren we deze?

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

Kopieer een array in ES6

let arrCopy = [...arr]; 

Kopieer n array in ES5

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

Waarom `Let ArcoPy = ARR` wordt niet door een waarde?

Het doorgeven van de ene variabele aan de andere op samengestelde waarden zoals Object/Array gedraagt zich anders. Door de operator toewijzen op copand-waarden te gebruiken, geven we een verwijzing door naar een object. Dit is de reden waarom de waarde van beide arrays verandert bij het verwijderen/toevoegen van arr-elementen.

Uitzonderingen:

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

Wanneer u een nieuwe waarde aan de variabele toewijst, wijzigt u de verwijzing zelf en heeft dit geen invloed op het oorspronkelijke object/array.

lees meer


Antwoord 12

Toevoegen aan de oplossing van array.slice();houd er rekening mee dat als je een multidimensionale arrayhebt, sub-arrays worden gekopieerd door verwijzingen.
Wat u kunt doen, is elke subarray afzonderlijk herhalen en slicen()

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]);

dezelfde dingen gelden voor een reeks objecten, ze worden gekopieerd door verwijzing, je moet ze handmatig kopiëren


Antwoord 13

let a = [1,2,3];

Je kunt nu een van de volgende dingen doen om een kopie van een array te maken.

let b = Array.from(a); 

OF

let b = [...a];

OF

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

OF

let b = a.slice(); 

OF

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

Als ik nu een verander,

a.push(5); 

A is dan [1,2,3,5] maar b is nog steeds [1,2,3] omdat het een andere referentie heeft.

Maar ik denk, in alle bovenstaande methodenArray.fromis beter en voornamelijk gemaakt om een array te kopiëren.


Antwoord 14

Ik zou persoonlijk de voorkeur geven aan deze manier:

JSON.parse(JSON.stringify( originalObject ));

Antwoord 15

Zoals we in Javascript weten, zijn arraysen objectenter referentie, maar op welke manieren kunnen we de array kopiëren zonder de originele array later te wijzigen?

Hier zijn enkele manieren om dit te doen:

Stel je voor dat we deze array in je code hebben:

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

1) Doorloop de array in een functie en retourneer een nieuwe array, zoals deze:

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

2) Slice met behulp van Slice-methode is Slice voor het snijden van een deel van de array, het zal een deel van uw array snijden zonder het origineel aan te raken, in de plak, als het het begin en het einde van de array niet wordt opgegeven, het zal Snijd de hele array en maak in principe een volledige kopie van de array, zodat we gemakkelijk kunnen zeggen:

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

3) Neem ook contactmethode contact op met de methode, dit is voor het samenvoegen van twee array, maar we kunnen gewoon een van de arrays opgeven en dan maakt dit in principe een kopie van de waarden in de nieuwe gecontacteerde array:

var arr2 = arr.concat();

4) Staart ook en parseren methode, het wordt niet aanbevolen, maar kan een eenvoudige manier zijn om array en objecten te kopiëren:

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

5) Array.van-methode, dit wordt niet veel ondersteund, vóór gebruik Controleer de ondersteuning in verschillende browsers:

const arr2 = Array.from(arr);

6) ECMA6 Way, ook niet volledig ondersteund, maar Babeljs kan u helpen als u wilt franspileren:

const arr2 = [...arr];

16

In mijn specifieke geval moest ik ervoor zorgen dat de array intact bleef dus dit werkte voor mij:

// 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]);
}

17

Kopie van multidimensionale array / object:

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;
}

Dankzij James Padolsey voor deze functie.

Bron: hier


18

Dan, niet nodig om mooie trucs te gebruiken. Het enige dat u hoeft te doen is kopie van ARR1 maken door dit te doen.

var arr1 = ['a','b','c'];
var arr2 = [];
var arr2 = new Array(arr1);
arr2.push('d');  // Now, arr2 = [['a','b','c'],'d']
console.log('arr1:');
console.log(arr1);
console.log('arr2:');
console.log(arr2);
// Following did the trick:
var arr3 = [...arr1];
arr3.push('d');  // Now, arr3 = ['a','b','c','d'];
console.log('arr3:');
console.log(arr3);

19

Als u een nieuwe kopie van een object of array wilt maken, moet u expliciet de eigenschappen van het object of de elementen van de array kopiëren, bijvoorbeeld:

var arr1 = ['a','b','c'];
var arr2 = [];
for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

Je kunt op Google zoeken naar meer informatie over onveranderlijke primitieve waarden en veranderlijke objectverwijzingen.


Antwoord 20

Als we een array willen kopiëren met behulp van de toewijzingsoperator ( =), wordt er geen kopie gemaakt, maar wordt alleen de aanwijzer/verwijzing naar de array gekopieerd. Bijvoorbeeld:

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

Antwoord 21

Het gebruik van jQuery deep copy kan als volgt worden gemaakt:

var arr2 = $.extend(true, [], arr1);

Antwoord 22

U kunt ook de ES6 spread-operator gebruiken om Array te kopiëren

var arr=[2,3,4,5];
var copyArr=[...arr];

Antwoord 23

Hier zijn nog enkele manieren om te kopiëren:

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 );

24

Voor ES6-array met objecten

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}

25

U kunt ES6 gebruiken met Spread OpArtor, de eenvoudiger.

arr2 = [...arr1];

Er zijn beperkingen ..check docs spreiding syntaxis @ Mozilla


26

Hier is een variant:

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
 */

Other episodes