Kopiranje i kloniranje objekata u JavaScriptu. Jedan 'novi' trik za pomoć svima nama.
Slaven Bunijevac
Posted on March 16, 2023
Kada se radi sa JavaScriptom, u bilo kom okruženju, jedan od prijedloga ili nepisanih pravila je da se ne mutira/mijenja originalni objekat. Najčešće je u pitanju npr. neki objekat koji je došao sa nekog endpointa, ali ne nužno. Može biti u pitanju bilo koji objekat, sa bilo kog izvora. Razlog je jednostavno u tome što je moguće da će neki drugi dio aplikacije odnosno programa koristiti isti taj objekat i nije dobro da se on mijenja.
Rješenje za takvo nešto je da se, naizgled jednostavno, napravi kopija tog objekta i da se mutira/mijenja ta kopija. Ali ovdje se radi o JavaScriptu, objekti su referentni tipovi, te stoga njihovo kopiranje nije tako jednostavna tema.
Šta ćete ovdje pročitati?
- Kako se objekti kopiraju u JavaScriptu?
- Kombinacija metoda
JSON.stringify
iJSON.parse
. - Spread
(...)
operator. - Nova metoda
structuredClone()
.
Kako se objekti kopiraju u Javascriptu?
Objekti u JavaScriptu su referentni tipovi podataka (za razliku od primitivnih; više o tipovima možete pričitati u ovom tekstu). Jedna od karakteristika referentnih tipova je da se oni kopiraju po referenci. Odnosno kada kopiramo jedan objekat u drugi, to znači da nismo kopirali njegov sadržaj u drugi objekat nego njegovu lokaciju u memoriji.
Ovdje smo kopirali objekat osoba1
u osoba2
ali smo kopirali njegovu referencu na lokaciju u memoriji. Ova dva objekta dijele sada tu referencu. Zato ako pokušamo da promijenimo jedan od ovih objekata automatski ćemo promijeniti i drugi. Zato što smo promijenili objekat u memoriji, a oba ova objekta upućuju na istu lokaciju u memoriji.
Promjena godina u objektu osoba2
je promijenila godine i u objektu osoba1
.
Dakle, u pokušaju da se pridržavamo pravila da ne mutiramo originalni objekat pravljenje obične kopije tog objekta neće funkcionisati. Zato je potrebno napraviti klon tog objekta, objekat koji ima sva svojstva kao i originalni objekat, ali koji ne dijeli njegovu referencu.
Kombinacija metoda JSON.stringify
i JSON.parse
Jedno od rješenja za pravljenje klon objekta u JavaScriptu je kombinovanje metoda JSON.stringify
i JSON.parse
.
JSON.stringify
metoda u JavaScriptu će uzeti objekat i pretvoriti ga u obični tekst, a JSON.parse
metoda će ga vratiti iz teksta u obični JavaScript objekat. Koristićemo naš postojeći objekat osoba1
.
Ova kombinacija metoda funkcioniše za neke osnovne potrebe. Međutim, problem kod ovog pristupa je što ne funkcioniše sa npr. datumima.
Kao što možemo viditi iz ovog primjera primjena metoda stringify
i parse
na datumu je promijenila taj datum. Naime, stringify
metoda je pretvorila datum u string u punom formatu, ali parse
metoda nije vratila taj string u puni datum, nego u ISO format.
Dakle, JSON.stringify
metoda je dobra kada radimo sa primitivnim tipovima kao što su string
, 'number' ili 'boolean'.
Evo nekliko primjera čudnog ponašanja:
Kada JSON.stringify
ne zna šta da radi sa nekim podacima može se lako dogoditi ili da izgubimo neke podatke ili da dobijemo nešto potpuno drugačije.
Spread (...)
operator
Sa ES6 standardom JavaScripta došao je jedan odličan operator koji se može koristiti za kloniranje objekata. To je 'spread' (...) operator. Kao što se vidi on izgleda kao obične tri tačke. Koristi se tako što se jednostavno postave tri tačke ispred objekta koji želimo da kopiramo i to dodamo kao vrijednost novom objektu.
Kao što se vidi iz osnovnog primjera moguće je koristiti i druge vrijednosti sa kojim smo imali problema u prethodnim primjerima. Vrijednosti su prenesene u drugi objekat onakve kakve su bile i u originalnom objektu. Datumi su u formatu koji smo imali i u originalnom objektu.
Naravno, ako promijenimo nešto u kloniranom objektu ta promjena se neće viditi u originalnom objektu.
Međutim, spread operator ima jednu, ali prilično veliku manu kada je kloniranje objekata u pitanju. Ta mana je što on pravi samo takozvane plitke kopije objekata. To znači da, ako neki objekat ima svojstvo koje je opet objekat, samo referenca tog 'unutrašnjeg' objekta će biti kopirana. Samim tim bilo koja promjena u tom unutrašnjem objektu će se odraziti i u unutrašnjem objektu originalnog objekta.
Ovo je veoma važna razlika jer ćete u stvarnosti često raditi sa objektima koji imaju više nivoa.
U ovom primjeru se vidi da objekat osoba1
ima svojstvo adresa
koji je i sam objekat, sa svojim svojstvima. Kada smo klonirali objekat osoba1
, objekat adresa
nije kloniran nego je samo kopirana njegova referenca. Zato, kada smo promijenili broj na adresi u kloniranom objektu, promijenili smo i broj na adresi u originalnom objektu.
S obzirom da je spread operator lično moj omiljeni način za kloniranje objekata, uvijek moram biti svjestan njegovog jednog velikog nedostatka i misliti na to koju će strukturu imati moj originalni objekat.
Nova metoda structuredClone()
Nešto što se dugo čekalo u JavaScriptu je metoda structured Clone
. Ova metoda je ugrađena u JavaScript u svim okruženjima. Koristi se tako što joj se kao parametar dodijeli objekat koji želimo da kopiramo i to se dodijeli kao vrijednost novom objekutu.
Kao što se vidi iz primjera structuredClone
može da se koristi sa specijalnim podacima kao što su Date
, Set
, sa funkcijama.
Metoda structuredClone
automatski pravi duboki klon datog objekta, bez obzira koliko nivoa je dubog objekat.
Svakako postoje i drugi načini koji se mogu koristiti za kopiranje objekata.
- Može se koristiti
Object.assign()
pristup. Ovo međutim takođe pravi plitku kopiju objekta. - Može se koristiti neka od biblioteka koje imaju rješenje za ovo. Jedna od njih je lodash. Ona ima svoju metodu
cloneDeep
koja može da posluži za kloniranje. Jedini problem je što morate uvesti cijelu biblioteku samo da bi dobili jednu metodu. Ako ne koristite ništa više iz bibliotekelodash
postoje bolja rješenja.
Posted on March 16, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.