Rozwiązywanie konkretnego problemu
Możesz użyć potwierdzenia typu, aby powiedzieć kompilatorowi, że wiesz lepiej:
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;
}
Klonowanie
Pamiętaj, że czasami lepiej jest napisać własne mapowanie, niż być całkowicie dynamicznym. Jest jednak kilka sztuczek „klonowania”, których możesz użyć, a które dają różne efekty.
Dla wszystkich kolejnych przykładów użyję następującego kodu:
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'));
Opcja 1: Spread
Właściwości: Tak
Metody: Nie
Głęboka kopia: Nie
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
Opcja 2: Object. assign
Właściwości: Tak
Metody: Nie
Głęboka kopia: Nie
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
Opcja 3: Object.create
Właściwości:
Metody dziedziczone
: Dziedziczone
Głębokie kopie: Płytkie Dziedziczone (głębokie zmiany wpływają na oryginał i klon)
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
Opcja 4: Funkcja głębokiego kopiowania
Właściwości: Tak
Metody: Nie
Głęboka kopia: Tak
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
cloned instanceof MyClass === true
?1. Użyj operatora rozprzestrzeniania
Operator rozłożenia pobiera wszystkie pola z obj1 i rozkłada je na obj2. W rezultacie otrzymujesz nowy obiekt z nowym odniesieniem i tymi samymi polami, co oryginalny.
Pamiętaj, że jest to płytka kopia, oznacza to, że jeśli obiekt jest zagnieżdżony, to jego zagnieżdżone parametry złożone będą istniały w nowym obiekcie przez to samo odniesienie.
2.Object. assign ()
Object.function tworzy prawdziwą kopię, ale tylko własne właściwości, więc właściwości w prototypie nie będą istnieć w kopiowanym obiekcie. Jest to również płytka kopia.
3.Object.create ()
Object.create
nie dokonuje prawdziwego klonowania , ale tworzy obiekt z prototypu. Dlatego użyj go, jeśli obiekt powinien klonować właściwości typu podstawowego, ponieważ przypisanie właściwości typu podstawowego nie jest wykonywane przez odwołanie.Plusy Object.create to, że wszelkie funkcje zadeklarowane w prototypie będzie dostępny w naszym nowo utworzonego obiektu.
Kilka rzeczy o płytkiej kopii
Płytka kopia umieszcza w nowym obiekcie wszystkie pola starego, ale oznacza to również, że jeśli oryginalny obiekt ma pola typu złożonego (obiekt, tablice itp.), To te pola są umieszczane w nowym obiekcie z tymi samymi odniesieniami. Mutacja takiego pola w oryginalnym obiekcie zostanie odzwierciedlona w nowym obiekcie.
Może to wygląda na pułapkę, ale tak naprawdę sytuacja, w której cały złożony obiekt wymaga skopiowania, jest rzadkością. Płytka kopia ponownie wykorzysta większość pamięci, co oznacza, że jest bardzo tania w porównaniu do głębokiej kopii.
Głęboka kopia
Operator rozprzestrzeniania może być przydatny w przypadku głębokiego kopiowania.
Powyższy kod utworzył głęboką kopię obj1. Pole złożone „złożone” zostało również skopiowane do obj2. Pole mutacji „złożone” nie będzie odzwierciedlać kopii.
źródło
Object.create(obj1)
tworzy nowy obiekt i przypisuje obj1 jako prototyp. Żadne z pól w obj1 nie jest kopiowane ani klonowane. Zatem zmiany w obj1 bez modyfikowania obj2 będą widoczne, ponieważ zasadniczo nie ma on żadnych właściwości. Jeśli najpierw zmodyfikujesz obj2, prototyp nie będzie widoczny dla zdefiniowanego pola, ponieważ pole obj2 o nazwie znajduje się bliżej w hierarchii.let b = Object.assign({}, a);
Spróbuj tego:
Jest to dobre rozwiązanie, dopóki nie używasz bardzo dużych obiektów lub Twój obiekt nie ma właściwości, których nie można serializować.
Aby zachować bezpieczeństwo typów, możesz użyć funkcji kopiowania w klasie, z której chcesz wykonać kopie:
lub w sposób statyczny:
źródło
undefined
wartością przynajmniej. jeśliobjectToCopy = { x : undefined};
po uruchomieniu twój kodObject.keys(objectToCopy).length
jest1
, whileObject.keys(copy).length
jest0
.TypeScript / JavaScript ma własny operator do płytkiego klonowania:
źródło
Łatwo jest uzyskać płytką kopię dzięki „Rozkładowi obiektów” wprowadzonemu w TypeScript 2.1
ten TypeScript:
let copy = { ...original };
tworzy ten JavaScript:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html
źródło
Dla serializowalnego głębokiego klonu, z informacją o typie,
źródło
JSON.stringify
clone
. :)undefined
wartością. Zobacz mój komentarz na temat podobnej odpowiedzi powyżej: stackoverflow.com/questions/28150967/typescript-cloning-object/…Moje zdanie na to:
Object.assign(...)
kopiuje tylko właściwości i tracimy prototyp i metody.Object.create(...)
to nie kopiowanie właściwości dla mnie i tylko tworzenie prototypu.Udało mi się stworzyć prototyp używając
Object.create(...)
i kopiując do niego właściwości używającObject.assign(...)
:Więc dla obiektu
foo
utwórz taki klon:źródło
foo
się prototypowym rodzicemclonedFoo
(nowego obiektu). Chociaż może to zabrzmieć dobrze, należy pamiętać, że brakująca właściwość zostanie wyszukana w łańcuchu prototypów, więcconst a = { x: 8 }; const c = Object.assign(Object.create(a), a); delete c.x; console.log(c.x);
wypisuje 8, a powinnoundefined
! (Link REPL: repl.it/repls/CompetitivePreemptiveKeygen )foo
, pojawi się ona automatycznie dlaclonedFoo
! np.foo.y = 9; console.log(clonedFoo.y)
wydrukuje9
zamiastundefined
. Jest bardzo prawdopodobne, że nie o to prosisz!Możesz też mieć coś takiego:
Po prostu upewnij się, że nadpisałeś
clone
metodę we wszystkichEntity
podklasach, w przeciwnym razie otrzymasz częściowe klony.Zwracany typ
this
zawsze będzie zgodny z typem instancji.źródło
Dodaj
"lodash.clonedeep": "^4.5.0"
do swojegopackage.json
. Następnie użyj w ten sposób:źródło
Oto mój mash-up! A tutaj jest łącze StackBlitz do niego. Obecnie ogranicza się tylko do kopiowania prostych typów i typów obiektów, ale myślę, że można je łatwo zmodyfikować.
źródło
typeof null
jest również obiektem, więcif (source[P] !== null && typeof source[P] === 'object')
zamiast tego zapytanie powinno być . W przeciwnym razie twoje wartości null zostaną zamienione w pusty obiekt.Jeśli pojawi się ten błąd:
To jest poprawny skrypt:
źródło
cloneObj[attribut] = this.clone();
? lub masz na myślicloneObj[attribut] = this[attribut].clone();
Sam przeszedłem przez ten problem i na koniec napisałem małą bibliotekę cloneable-ts, która zapewnia klasę abstrakcyjną, która dodaje metodę clone do każdej klasy rozszerzającej ją. Klasa abstrakcyjna pożycza funkcję Deep Copy opisaną w zaakceptowanej odpowiedzi przez Fentona, zastępując ją jedynie
copy = {};
wcopy = Object.create(originalObj)
celu zachowania klasy oryginalnego obiektu. Oto przykład użycia klasy.Lub możesz po prostu użyć
Cloneable.clone
metody pomocniczej:źródło
Od czasu wydania TypeScript 3.7 obsługiwane są rekursywne aliasy typów, co pozwala nam zdefiniować funkcję bezpieczną dla typu
deepCopy()
:Plac zabaw
źródło
Aby uzyskać prosty klon zawartości obiektu hole, po prostu określam i analizuję instancję:
Podczas gdy zmieniam dane w drzewie objectToClone, nie ma zmiany w cloneObject. To było moje wymaganie.
Mam nadzieję, że to pomoże
źródło
undefined
wartością. Zobacz mój komentarz na temat podobnej odpowiedzi powyżej: stackoverflow.com/questions/28150967/typescript-cloning-object/…Skończyło się na zrobieniu:
Ponieważ:
z @Fenton podał błędy uruchomieniowe.
Wersja maszynopisu: 2.4.2
źródło
A może stary dobry jQuery ?! Oto głęboki klon:
źródło
Podjęłam próbę stworzenia ogólnej usługi kopiowania / klonowania, która zachowuje typy dla zagnieżdżonych obiektów. Chciałbym otrzymać informację zwrotną, jeśli robię coś źle, ale wydaje się, że jak dotąd działa ...
źródło
W typeScript testuję z angularem i działa OK
źródło
Do głębokiego klonowania obiektu, który może zawierać inne obiekty, tablice itd., Używam:
Posługiwać się:
źródło
Możesz użyć destrukcyjnego przypisania ze składnią rozprzestrzeniania :
źródło
Jeśli masz już obiekt docelowy, więc nie chcesz tworzyć go od nowa (jak w przypadku aktualizacji tablicy), musisz skopiować właściwości.
Jeśli zrobiłeś to w ten sposób:
Pochwała jest należna. (spójrz na nagłówek „wersja 2”)
źródło