DEV Community

Slaven Bunijevac
Slaven Bunijevac

Posted on

Kopiranje i kloniranje objekata u JavaScriptu. Jedan 'novi' trik za pomoć svima nama.

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 i JSON.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.

copy an object to another one in JavaScript

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.

change value in copied object in JavaScript

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.

parse and stringify to clone an object in JavaScript

Ova kombinacija metoda funkcioniše za neke osnovne potrebe. Međutim, problem kod ovog pristupa je što ne funkcioniše sa npr. datumima.

parsing date from string in JavaScript

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:

JSON.stringify in JavaScript bad behaviour

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.

spread object into another object in JavaScript

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.

change key in object after spread in JavaScript

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.

spread creating a shallow copy in JavaScript

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.

structuredClone example in JavaScript

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 biblioteke lodash postoje bolja rješenja.

Top comments (0)