Ich habe eine Reihe von zwei Objekten:
genericItems: Item[] = [];
backupData: Item[] = [];
Ich fülle meine HTML-Tabelle mit genericItems
Daten. Die Tabelle kann geändert werden. Es gibt eine Reset-Taste, um alle vorgenommenen Änderungen rückgängig zu machen backUpData
. Dieses Array wird von einem Dienst gefüllt:
getGenericItems(selected: Item) {
this.itemService.getGenericItems(selected).subscribe(
result => {
this.genericItems = result;
});
this.backupData = this.genericItems.slice();
}
Meine Idee war, dass die Benutzeränderungen im ersten Array wiedergegeben werden und das zweite Array als Backup für den Reset-Vorgang verwendet werden kann. Das Problem, mit dem ich hier konfrontiert bin, ist, wenn der Benutzer die Tabelle ändert ( genericItems[])
das zweite Array wird backupData
ebenfalls geändert.
Wie passiert das und wie kann man das verhindern?
arrays
angular
typescript
Arun
quelle
quelle
slice()
wird ein neues Objekt aus einem anderen Array erstellen, denke ich ...slice
nimmt ein Array und kopiert jede Referenz in ein neues Array. Das alte und das neue Array unterscheiden sich also tatsächlich, aber die darin enthaltenen Objekte sind genau gleich. Also sollte es das gleiche sein wie zu tun[...array]
Antworten:
Ein Objekt klonen:
const myClonedObject = Object.assign({}, myObject);
Klonen eines Arrays:
const myClonedArray = Object.assign([], myArray);
const myArray= [{ a: 'a', b: 'b' }, { a: 'c', b: 'd' }]; const myClonedArray = []; myArray.forEach(val => myClonedArray.push(Object.assign({}, val)));
quelle
const myArray= [{ a: 'a', b: 'b' }, { a: 'c', b: 'd' }]; const myClonedArray = []; myArray.map(val => myClonedArray.push(Object.assign({}, val)));
. Eine alternative Lösung für eine ordnungsgemäße Tiefenkopie wäre die JSON-Serialisierung, wie in anderen Antworten erwähnt._.cloneDeep(obj)
. Die JSON-Serialisierung würde funktionieren, wie Sie sagten, aber das ist ein sehr umständlicher Weg, dies zu tun.Das Klonen von Arrays und Objekten in Javascript hat eine andere Syntax . Früher oder später lernt jeder den Unterschied auf die harte Tour und landet hier.
In Typescript und ES6 können Sie den Spread-Operator für Array und Objekt verwenden:
const myClonedArray = [...myArray]; // This is ok for [1,2,'test','bla'] // But wont work for [{a:1}, {b:2}]. // A bug will occur when you // modify the clone and you expect the // original not to be modified. // The solution is to do a deep copy // when you are cloning an array of objects.
Um eine tiefe Kopie eines Objekts zu erstellen, benötigen Sie eine externe Bibliothek:
import {cloneDeep} from 'lodash'; const myClonedArray = cloneDeep(myArray); // This works for [{a:1}, {b:2}]
Der Spread-Operator arbeitet auch mit Objekten, erstellt jedoch nur eine flache Kopie (erste untergeordnete Ebene).
const myShallowClonedObject = {...myObject}; // Will do a shallow copy // and cause you an un expected bug.
Um eine tiefe Kopie eines Objekts zu erstellen, benötigen Sie eine externe Bibliothek:
import {cloneDeep} from 'lodash'; const deeplyClonedObject = cloneDeep(myObject); // This works for [{a:{b:2}}]
quelle
Die Verwendung einer Karte oder einer ähnlichen Lösung hilft nicht dabei, ein Array von Objekten tief zu klonen. Eine einfachere Möglichkeit, dies ohne Hinzufügen einer neuen Bibliothek zu tun, ist die Verwendung von JSON.stringfy und anschließend von JSON.parse.
In Ihrem Fall sollte dies funktionieren:
this.backupData = JSON.parse(JSON.stringify(genericItems));
Für kleine Objekte kann lodone cloneDeep schneller sein, aber für größere / tiefere Objekte wird json clone schneller. In diesen Fällen sollten Sie nicht zögern, es zu verwenden. Überprüfen Sie https://www.measurethat.net/Benchmarks/Show/6039/0/lodash-clonedeep-vs-json-clone-larger-object und auf Informationen https://v8.dev/blog/cost-of-javascript -2019 # json
Der Nachteil ist, dass Ihr Quellobjekt in JSON konvertierbar sein muss.
quelle
Versuchen Sie den folgenden Code:
this.cloneArray= [...this.OriginalArray]
quelle
Die folgende Zeile in Ihrem Code erstellt ein neues Array, kopiert alle Objektreferenzen
genericItems
in dieses neue Array und weist es zubackupData
:this.backupData = this.genericItems.slice();
Während
backupData
undgenericItems
sind verschiedene Arrays, enthalten sie die gleichen exakten Objektreferenzen.Sie könnten eine Bibliothek mitbringen, um tiefes Kopieren für Sie durchzuführen (wie @LatinWarrior erwähnt).
Aber wenn
Item
es nicht zu komplex ist, können Sie vielleicht eineclone
Methode hinzufügen , um das Objekt selbst tief zu klonen:class Item { somePrimitiveType: string; someRefType: any = { someProperty: 0 }; clone(): Item { let clone = new Item(); // Assignment will copy primitive types clone.somePrimitiveType = this.somePrimitiveType; // Explicitly deep copy the reference types clone.someRefType = { someProperty: this.someRefType.someProperty }; return clone; } }
Rufen Sie dann
clone()
jeden Artikel an:this.backupData = this.genericItems.map(item => item.clone());
quelle
Ich habe das gleiche Problem mit primeNg DataTable. Nachdem ich es versucht und geweint habe, habe ich das Problem mithilfe dieses Codes behoben.
private deepArrayCopy(arr: SelectItem[]): SelectItem[] { const result: SelectItem[] = []; if (!arr) { return result; } const arrayLength = arr.length; for (let i = 0; i <= arrayLength; i++) { const item = arr[i]; if (item) { result.push({ label: item.label, value: item.value }); } } return result; }
Zum Initialisieren des Sicherungswerts
backupData = this.deepArrayCopy(genericItems);
Zum Zurücksetzen von Änderungen
genericItems = this.deepArrayCopy(backupData);
Das Wundermittel besteht darin, Elemente mithilfe
{}
des Konstruktors neu zu erstellen, anstatt ihn aufzurufen. Ich habe versucht,new SelectItem(item.label, item.value)
was nicht funktioniert.quelle
Sie können die Kartenfunktion verwenden
toArray= fromArray.map(x => x);
quelle
Versuche dies:
[https://lodash.com/docs/4.17.4#clone][1] var objects = [{ 'a': 1 }, { 'b': 2 }]; var shallow = _.clone(objects); console.log(shallow[0] === objects[0]); // => true
quelle
Es sieht so aus, als hätten Sie einen Fehler gemacht, wo Sie die Kopie eines Arrays erstellen. Schauen Sie sich meine Erklärung unten und eine geringfügige Änderung des Codes an, die Ihnen dabei helfen soll, die Daten auf den vorherigen Status zurückzusetzen.
In Ihrem Beispiel kann ich Folgendes sehen:
Habe ich Recht, wenn ich denke, dass Sie nicht möchten, dass der dritte Punkt in dieser Reihenfolge passiert?
Wäre das besser:
Versuche dies:
getGenericItems(selected: Item) { this.itemService.getGenericItems(selected).subscribe( result => { // make a backup before you change the genericItems this.backupData = this.genericItems.slice(); // now update genericItems with the results from your request this.genericItems = result; }); }
quelle
Der folgende Code kann Ihnen beim Kopieren der Objekte der ersten Ebene helfen
let original = [{ a: 1 }, {b:1}] const copy = [ ...original ].map(item=>({...item}))
Für den folgenden Fall bleiben die Werte also intakt
copy[0].a = 23 console.log(original[0].a) //logs 1 -- value didn't change voila :)
Schlägt für diesen Fall fehl
let original = [{ a: {b:2} }, {b:1}] const copy = [ ...original ].map(item=>({...item})) copy[0].a.b = 23; console.log(original[0].a) //logs 23 -- lost the original one :(
Abschließender Rat:
Ich würde sagen, entscheiden Sie sich für die lodash-
cloneDeep
API, mit der Sie die Objekte in Objekten kopieren können, die vollständig von den ursprünglichen Objekten abweichen . Dies kann als separates Modul installiert werden.Siehe Dokumentation: https://github.com/lodash/lodash
Einzelpaket : https://www.npmjs.com/package/lodash.clonedeep
quelle
Der einfachste Weg, ein Array zu klonen, ist
Dadurch wird ein neuer Speicher für die Array-Indizes erstellt
quelle
backUpData
.backUpData
hält noch Referenz vongenericItems
.Wenn Ihre Elemente im Array nicht primitiv sind, können Sie dazu den Spread-Operator verwenden.
this.plansCopy = this.plans.map(obj => ({...obj}));
Vollständige Antwort: https://stackoverflow.com/a/47776875/5775048
quelle
Sieht so aus, als ob Sie eine tiefe Kopie des Objekts wünschen . Warum nicht verwenden
Object.assign()
? Keine Bibliotheken benötigt, und es ist ein Einzeiler :)getGenericItems(selected: Item) { this.itemService.getGenericItems(selected).subscribe( result => { this.genericItems = result; this.backupDate = Object.assign({}, result); //this.backupdate WILL NOT share the same memory locations as this.genericItems //modifying this.genericItems WILL NOT modify this.backupdate }); }
Weitere Informationen finden Sie unter
Object.assign()
: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assignquelle
slice()
. Es wird ein neues Array erstellt, aber die Objektreferenzen werden aus dem alten Array kopiert.Object.assign([], result)
. Ansonsten denke ich, dass Sie daslength
Eigentum verlieren werden (und vielleicht einige andere Dinge).Versuche dies
const returnedTarget = Object.assign(target, source);
und übergeben Sie ein leeres Array an das Ziel
Für den Fall, dass komplexe Objekte auf diese Weise für mich funktionieren
$.extend(true, [], originalArray)
im Falle eines Arrays$.extend(true, {}, originalObject)
im Falle eines Objektsquelle