๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป DEV/Javascript & NodeJS

[Javascript] ๊ฐ์ฒด์˜ Deep Copy (๊นŠ์€ ๋ณต์‚ฌ)

by vodkassi 2021. 5. 9.
728x90

โœจ Object ๋ž€?

Javascript์˜ Reference type (๊ฐ์ฒด/์ฐธ์กฐํ˜• ํƒ€์ž…) ์— ์†ํ•˜๋Š” Data type ์ด๋‹ค.

ํ•œ๊ตญ์–ด๋กœ๋Š” '๊ฐ์ฒด'๋กœ ๋ถˆ๋ฆฌ์šฐ๋ฉฐ, key ์™€ value ๋“ค๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

๊ฐ์ฒด๋Š” Heap ๋ผ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ์ €์žฅ๋˜๋ฉฐ, ๋ณ€์ˆ˜์—๋Š” ํ•ด๋‹น ๊ณต๊ฐ„์„ ์ฐธ์กฐํ•˜๋Š” ์ฃผ์†Œ๊ฐ’์ด ํ• ๋‹น๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜์— ๊ฐ์ฒด ๋ณ€์ˆ˜ ์ž์ฒด๋ฅผ ํ• ๋‹นํ•  ๊ฒฝ์šฐ ๊ฐ์ฒด ์ž์ฒด์˜ ๋ณต์‚ฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š์œผ๋ฉฐ, ๊ฐ์ฒด๋ฅผ ๋ฐ”๋ผ๋ณด๋Š” ์ฃผ์†Œ๋งŒ ๋ณต์‚ฌ๋œ๋‹ค.

 

// ์ฐธ์กฐ ํ• ๋‹น: ์„œ๋กœ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋จ
let obj = {0:'zero', 1:'one'}
let obj1 = obj // obj์˜ ๊ฐ์ฒด ์ฃผ์†Œ๊ฐ€ ๋ณต์‚ฌ๋จ 
obj1.1 = 'changed one' // obj1 ์—์„œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด 
obj // {0:'zero', 1:'changed one'} 
// obj ์—์„œ๋„ ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โœจ Light(Shallow) Copy ๋ž€?

๊ฐ์ฒด๋ฅผ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋กœ ๋ณต์‚ฌํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ด๋‹ค. Object.assign() ๋˜๋Š” Spread Operator ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ์‹œ๋Š” Object.assign()์„ ํ™œ์šฉํ•˜์—ฌ ์ž‘์„ฑํ•ด๋ณธ๋‹ค.

 

let obj = { a: 1, b: 2} // ์ถœ์ฒ˜ ๊ฐ์ฒด
let target = { c: 3 } // ๋Œ€์ƒ ๊ฐ์ฒด

let newobj = Object.assign(target, obj)
newobj // { c: 3, a: 1, b: 2 }

 

์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์˜ ๋ฌธ์ œ์ ์€ ๊ฐ์ฒด์˜ ์™„์ „ํ•œ ๋ณต์‚ฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

 

let obj = { a: 1, b: 2, c: {d:3, e:4}} // ์ถœ์ฒ˜ ๊ฐ์ฒด 
let newobj = Object.assign({}, obj) // ์ถœ์ฒ˜ ๊ฐ์ฒด๋ฅผ ๋นˆ ๊ฐ์ฒด์— ๋ณต์‚ฌํ•ด์ค€๋‹ค

obj.a = 100 // ์›๋ณธ ๊ฐ์ฒด์˜ ์†์„ฑ๊ฐ’ ๋ณ€๊ฒฝ  
obj.c.d = 300 // ์›๋ณธ ๊ฐ์ฒด์˜ ์†์„ฑ๊ฐ’ ๋ณ€๊ฒฝ

newobj.a // 1  
newobj.c.d // 300

 

์ด์ฒ˜๋Ÿผ ๊ฐ์ฒด์˜ ์†์„ฑ์œผ๋กœ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ํ•ด๋‹น key ์—๋Š” ์ฐธ์กฐํ•˜๋Š” ์ฃผ์†Œ๊ฐ€ ํ• ๋‹น๋œ๋‹ค.

 

์ฐธ๊ณ ) 

MDN ์„ค๋ช…: “For deep cloning, we need to use alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value.”

 

โœจ Deep Copy ๋ž€?

์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก, ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ ์—†์ด ๊ณ ์œ ๊ฐ’๋งŒ ์ „๋ถ€ ๋ณต์‚ฌํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์˜๋ฏธํ•œ๋‹ค.

 

JSON.stringify ์™€ JSON.parse ๋ฅผ ํ™œ์šฉํ•˜๋ฉด Deep copy ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

JSON.Stringify ๋Š” ๋ฐ›์•„์˜จ iterable ์„ String์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋ฉฐ, JSON.parse ๋Š” ๋ณ€ํ™˜๋œ ๋ฌธ์ž๋ฅผ ๋‹ค์‹œ ๊ฐ์ฒด๋กœ ๋˜๋Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

let obj = { a: 1, b: 2, c: {d:3, e:4}} 
let newobj = JSON.parse(JSON.stringify(obj))  
// ๋ณ€ํ™˜ ์‹œ ์ด์ „ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์‚ฌ๋ผ์ง
obj.a = 100 // ์›๋ณธ ๊ฐ์ฒด์˜ ์†์„ฑ๊ฐ’ ๋ณ€๊ฒฝ
obj.c.d = 300 // ์›๋ณธ ๊ฐ์ฒด์˜ ์†์„ฑ๊ฐ’ ๋ณ€๊ฒฝ

newobj.a // 1
newobj.c.d // 3

 

์ด ๋ฐฉ๋ฒ•์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์ ๋“ค์ด ์กด์žฌํ•œ๋‹ค.

- BigInt (ECMA 2020 ๋„์ž…) ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค. (์—๋Ÿฌ ๋ฐ˜ํ™˜)

- Date์™€ ๊ฐ™์€ ๊ฐ์ฒด๋Š” Stringify ์ ์šฉ ์‹œ ๋ณด์—ฌ์ง€๋Š” ๋ฐฉ์‹๋„ ๋ณ€ํ™˜ํ•œ๋‹ค.

- ํ•จ์ˆ˜, ์ •๊ทœํ‘œํ˜„์‹, Infinity ๋“ฑ์˜ ๋ฐ์ดํ„ฐ ์—ญ์‹œ ๋ณ€ํ™˜์ด ์•ˆ ๋œ๋‹ค.

- ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์— ๋น„ํ•ด ์†๋„๊ฐ€ ๋Š๋ฆฌ๋‹ค.

 

โœจ Lodash

 

Lodash ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” cloneDeep() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด Deep Copy ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•œ๋‹ค. ์ด๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์†์‰ฝ๊ฒŒ Deep Copy ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

import * as _ from 'lodash' 

const object1 = { a: 1, b: 2 }; 
const object2 = \_.cloneDeep(object1); 
object2.a = 100; console.log(object2.a); //100 console.log(object2.b); //2

 

 

์œ„์˜ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์™ธ์—๋„ ์ง์ ‘ for ๋ฌธ์„ ๋Œ๋ฆฌ๋ฉฐ ์ƒˆ๋กœ์šด ๊ฐ์ฒด์— ๋ณต์‚ฌ๋ฅผ ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

โœจ ๋งˆ๋ฌด๋ฆฌ

Deep Copy ๋ผ๊ณ  ๋ฌด์กฐ๊ฑด ์ข‹์€ ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ, Shallow Copy ๋ผ๊ณ  ๋ฌด์กฐ๊ฑด ๊ธฐํ”ผํ•ด์•ผ ํ•  ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ฝ”๋“œ์˜ ๋ชฉ์ ๊ณผ ๊ฐ์ฒด์˜ ์šฉ๋„์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ด๋‹ค.

 

์ฐธ๊ณ ์ž๋ฃŒ

๊นŠ์€ ๋ณต์‚ฌ์™€ ์–•์€ ๋ณต์‚ฌ์— ๋Œ€ํ•œ ์‹ฌ๋„์žˆ๋Š” ์ด์•ผ๊ธฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด ๋ณต์‚ฌํ•˜๊ธฐ

Lodash | _.cloneDeep() Method

๋Œ“๊ธ€