Lösen des spezifischen Problems
Sie können eine Typzusicherung verwenden, um dem Compiler mitzuteilen, dass Sie es besser wissen:
public clone(): any {
var cloneObj = new (this.constructor() as any);
for (var attribut in this) {
if (typeof this[attribut] === "object") {
cloneObj[attribut] = this[attribut].clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
Klonen
Denken Sie daran, dass es manchmal besser ist, ein eigenes Mapping zu schreiben, als völlig dynamisch zu sein. Es gibt jedoch einige "Klon" -Tricks, mit denen Sie unterschiedliche Effekte erzielen können.
Ich werde den folgenden Code für alle nachfolgenden Beispiele verwenden:
class Example {
constructor(public type: string) {
}
}
class Customer {
constructor(public name: string, public example: Example) {
}
greet() {
return 'Hello ' + this.name;
}
}
var customer = new Customer('David', new Example('DavidType'));
Option 1: Ausbreiten
Eigenschaften: Ja
Methoden: Nein
Deep Copy: Nein
var clone = { ...customer };
alert(clone.name + ' ' + clone.example.type); // David DavidType
//alert(clone.greet()); // Not OK
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
Option 2: Object.assign
Eigenschaften: Ja
Methoden: Nein
Deep Copy: Nein
var clone = Object.assign({}, customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // Not OK, although compiler won't spot it
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
Option 3: Object.create
Eigenschaften: Vererbt
Methoden: Vererbt
Tiefe Kopie: Flach Vererbt (tiefe Änderungen wirken sich sowohl auf das Original als auch auf den Klon aus)
var clone = Object.create(customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // OK
customer.name = 'Misha';
customer.example = new Example("MishaType");
// clone sees changes to original
alert(clone.name + ' ' + clone.example.type); // Misha MishaType
clone.name = 'Steve';
clone.example.type = 'SteveType';
// original sees changes to clone
alert(customer.name + ' ' + customer.example.type); // Misha SteveType
Option 4: Deep Copy-Funktion
Eigenschaften: Ja
Methoden: Nein
Deep Copy: Ja
function deepCopy(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = deepCopy(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
var clone = deepCopy(customer) as Customer;
alert(clone.name + ' ' + clone.example.type); // David DavidType
// alert(clone.greet()); // Not OK - not really a customer
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David DavidType
1.Verwenden Sie den Spread-Operator
Der Spread-Operator nimmt alle Felder aus obj1 und verteilt sie über obj2. Im Ergebnis erhalten Sie ein neues Objekt mit einer neuen Referenz und denselben Feldern wie das ursprüngliche.
Denken Sie daran, dass es sich um eine flache Kopie handelt. Wenn ein Objekt verschachtelt ist, sind seine verschachtelten zusammengesetzten Parameter im neuen Objekt mit derselben Referenz vorhanden.
2.Object.assign ()
Object.assign erstellt eine echte Kopie, jedoch nur eigene Eigenschaften, sodass Eigenschaften im Prototyp im kopierten Objekt nicht vorhanden sind. Es ist auch eine flache Kopie.
3.Object.create ()
Object.create
führt kein echtes Klonen durch , sondern erstellt ein Objekt aus einem Prototyp. Verwenden Sie es daher, wenn das Objekt Eigenschaften des Primärtyps klonen soll, da die Zuweisung der Eigenschaften des Primärtyps nicht als Referenz erfolgt.Pluspunkte von Object.create sind, dass alle im Prototyp deklarierten Funktionen in unserem neu erstellten Objekt verfügbar sind.
Einige Dinge über flache Kopien
Bei einer flachen Kopie werden alle Felder des alten in ein neues Objekt eingefügt. Wenn das ursprüngliche Objekt jedoch zusammengesetzte Felder (Objekt, Arrays usw.) enthält, werden diese Felder in ein neues Objekt mit denselben Referenzen eingefügt. Die Mutation eines solchen Feldes im ursprünglichen Objekt wird in einem neuen Objekt wiedergegeben.
Es sieht vielleicht wie eine Falle aus, aber eine Situation, in der das gesamte komplexe Objekt kopiert werden muss, ist selten. Flache Kopien verwenden den größten Teil des Speichers wieder, was bedeutet, dass dies im Vergleich zu tiefen Kopien sehr billig ist.
Tiefe Kopie
Der Spread-Operator kann für tiefe Kopien nützlich sein.
Über dem Code wurde eine tiefe Kopie von obj1 erstellt. Das zusammengesetzte Feld "Komplex" wurde ebenfalls in obj2 kopiert. Das Mutationsfeld "komplex" spiegelt die Kopie nicht wider.
quelle
Object.create(obj1)
erstellt ein neues Objekt und weist obj1 als Prototyp zu. Keines der Felder in obj1 wird kopiert oder geklont. Änderungen an obj1 ohne Änderung von obj2 werden also angezeigt, da es im Wesentlichen keine Eigenschaften hat. Wenn Sie zuerst obj2 ändern, wird der Prototyp für das von Ihnen definierte Feld nicht angezeigt, da das Feld von obj2 mit dem Namen näher in der Hierarchie liegt.let b = Object.assign({}, a);
Versuche dies:
Dies ist eine gute Lösung, bis Sie sehr große Objekte verwenden oder Ihr Objekt unserialisierbare Eigenschaften hat.
Um die Typensicherheit zu gewährleisten, können Sie eine Kopierfunktion in der Klasse verwenden, von der Sie Kopien erstellen möchten:
oder statisch:
quelle
undefined
zumindest zu fehlenden Schlüsseln mit Wert führen. WennobjectToCopy = { x : undefined};
dann nach dem Ausführen Ihr CodeObject.keys(objectToCopy).length
ist1
, währendObject.keys(copy).length
ist0
.TypeScript / JavaScript hat einen eigenen Operator für das flache Klonen:
quelle
Mit "Object Spread", das in TypeScript 2.1 eingeführt wurde, ist es einfach, eine flache Kopie zu erhalten
dieses TypeScript:
let copy = { ...original };
erzeugt dieses JavaScript:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html
quelle
Für serialisierbare tiefe Klone mit Typinformationen gilt:
quelle
JSON.stringify
clone
. :)undefined
Wert verfehlen . Siehe meinen Kommentar zu der ähnlichen Antwort oben: stackoverflow.com/questions/28150967/typescript-cloning-object/…Meine Meinung dazu:
Object.assign(...)
kopiert nur Eigenschaften und wir verlieren den Prototyp und die Methoden.Object.create(...)
kopiert für mich keine Eigenschaften und erstellt nur einen Prototyp.Für mich hat es funktioniert, einen Prototyp zu erstellen
Object.create(...)
und Eigenschaften zu kopieren, indem ichObject.assign(...)
:Erstellen Sie für ein Objekt
foo
einen Klon wie folgt:quelle
foo
das prototypische Elternteil desclonedFoo
(neuen Objekts). Dies mag zwar in Ordnung klingen, Sie sollten jedoch berücksichtigen, dass eine fehlende Eigenschaft in der Prototypenkette nachgeschlagen wird.const a = { x: 8 }; const c = Object.assign(Object.create(a), a); delete c.x; console.log(c.x);
Drucken Sie also 8 aus, solange dies der Fall sein sollteundefined
! (REPL-Link: repl.it/repls/CompetitivePreemptiveKeygen )foo
, wird diese automatisch fürclonedFoo
angezeigt! zBfoo.y = 9; console.log(clonedFoo.y)
wird auszudrucken9
von stattundefined
. Es ist sehr wahrscheinlich, dass es nicht das ist, wonach Sie fragen!Sie können auch so etwas haben:
Stellen Sie einfach sicher, dass Sie die
clone
Methode in allenEntity
Unterklassen überschreiben, da Sie sonst teilweise Klone erhalten.Der Rückgabetyp von entspricht
this
immer dem Typ der Instanz.quelle
Wenn Sie diesen Fehler erhalten:
Dies ist das richtige Skript:
quelle
cloneObj[attribut] = this.clone();
? oder du meinstcloneObj[attribut] = this[attribut].clone();
Ich bin auf dieses Problem selbst gestoßen und habe am Ende eine kleine Bibliothek geschrieben, die klonbar ist und eine abstrakte Klasse bereitstellt, die jeder Klasse, die sie erweitert, eine Klonmethode hinzufügt. Die abstrakte Klasse leiht ich die Deep Copy - Funktion in der akzeptierten Antwort beschrieben durch Fenton nur ersetzt
copy = {};
mitcopy = Object.create(originalObj)
der Klasse des ursprünglichen Objekts zu erhalten. Hier ist ein Beispiel für die Verwendung der Klasse.Oder Sie können einfach die
Cloneable.clone
Hilfsmethode verwenden:quelle
Hier ist mein Mash-up! Und hier ist ein StackBlitz-Link dazu. Es beschränkt sich derzeit nur auf das Kopieren einfacher Typen und Objekttypen, könnte aber meiner Meinung nach leicht geändert werden.
quelle
typeof null
jedoch auch ein Objekt, sollte die Abfrageif (source[P] !== null && typeof source[P] === 'object')
stattdessen sein. Andernfalls werden Ihre Nullwerte in ein leeres Objekt umgewandelt.Fügen Sie
"lodash.clonedeep": "^4.5.0"
Ihrem hinzupackage.json
. Dann verwenden Sie wie folgt:quelle
Seit der Veröffentlichung von TypeScript 3.7 werden jetzt rekursive Typaliasnamen unterstützt, mit denen wir eine typsichere
deepCopy()
Funktion definieren können:Spielplatz
quelle
Für einen einfachen Klon des Inhalts des Hole-Objekts werde ich die Instanz einfach stringifizieren und analysieren:
Während ich Daten im objectToClone-Baum ändere, gibt es in cloneObject keine Änderung. Das war meine Anforderung.
Hoffe es hilft
quelle
undefined
Wert verfehlen . Siehe meinen Kommentar zu der ähnlichen Antwort oben: stackoverflow.com/questions/28150967/typescript-cloning-object/…Am Ende tat ich:
Weil:
von @Fenton gab Laufzeitfehler.
Typoskript-Version: 2.4.2
quelle
Wie wäre es mit guter alter jQuery?! Hier ist ein tiefer Klon:
quelle
Ich habe versucht, einen generischen Kopier- / Klondienst zu erstellen, der Typen für verschachtelte Objekte beibehält. Würde mich über Feedback freuen, wenn ich etwas falsch mache, aber es scheint soweit zu funktionieren ...
quelle
In TypeScript teste ich mit Angular und es geht OK
quelle
Zum tiefen Klonen eines Objekts, das andere Objekte, Arrays usw. enthalten kann, verwende ich:
Verwenden:
quelle
Sie können die Destrukturierungszuweisung mit Spread-Syntax verwenden :
quelle
Wenn Sie das Zielobjekt bereits haben und es nicht neu erstellen möchten (z. B. beim Aktualisieren eines Arrays), müssen Sie die Eigenschaften kopieren.
Wenn Sie es so gemacht haben:
Lob gebührt. (siehe Überschrift "Version 2")
quelle