[javascript] 어라, 객체를 복사했는데 이상하네?🤔깊은복사와 얕은복사를 알아보자

javascript
블로그 이미지

이챙(leechaeng)

﹒2022. 4. 21.

객체를 다루다보면 복사를 하고 싶은 경우가 생기는데요 복사에도 두가지의 개념이 있어요. 깊은복사(Deep copy) 얕은복사(Shallow copy)! 그 전에 자바스크립트에서 원시타입과 참조타입에 대해서 알고 있어야 합니다. 간단하게 알아보고 넘어가죠

 

자바스크립트에서 원시타입엔 Number, BigInt, String, Boolean, Null, Undefined, Symbol 7 개의 타입이 있고 그 외는 객체(참조)타입으로 이루어져 있습니다.

 

🔹원시타입은 변수에 값 자체를 할당

num변수에 100을 할당하면 변수 메모리 공간에 값 자체가 할당이 되요 그렇기 때문에 num2에 num 값을 대입하고 num의 값을 바꿔도 num2는 그대로 값 100을 유지합니다



🔹참조타입은 변수에 참조값(메모리 주소)을 할당

객체 obj에 a프로퍼티에 값 1을 할당시켜 주었어요 그리고 obj2 변수에 obj객체를 대입해주었습니다. 두 변수는 af2gd라는 참조값(메모리주소)를 담고있는 상태가 됩니다. 두 변수가 동시에 af2gd만 바라보고 있는거죠. obj2.a의 값을 2로 바꾸면 obj.a의 값을 어떻게 될까요? 바로 값 2로 됩니다. 원시값은 값 자체를 변수에 할당시키는 반면에 객체는 참조값(메모리주소)을 변수에 할당시키고 있다는 걸 확인 할 수 있습니다





📃얕은 복사(Shallow Copy)

원본을 그대로 복사하지만 원본값과 복사된 값이 같이 참조(같은 메모리주소)되고 있는 상태를 얕은 복사라고 합니다. 객체안에 객체가 있을때 얕은복사의 단점(?)이 일어나요
얕은 복사의 여러가지 방법중에 2개의 방법으로 어떻게 얕은복사가 되고 있는지 확인해봅시다


1. Array.prototype.slice()

const arr = [{},1,2,3]
const arr2 = arr.slice()

arr2[0].a = 5

console.log(arr === arr2) //false
console.log(arr2[0] === arr[0]) //true


arr2변수에 arr을 복사하고 둘을 비교해봤더니 false가 나와요. 얕은복사를 했으니 둘은 다른거라고 나오겠죠? 하지만 arr2의 첫번째 값인 빈 객체에 프로퍼티 a를 추가했더니 원본배열인 arr에도 프로퍼티a가 추가되었습니다. 바로 이것이 객체가 얕은복사가 되고 있는겁니다.


2. Spread Operator(전개연산자)

const obj = {
    a:[],
    b:1,
    c:2
}
const obj2 = {...obj}

obj2.a.push(5)

console.log(obj === obj2) //false
console.log(obj.a === obj2.a) //true


이번엔 객체를 전개연산자로 얕은복사를 해볼게요. 원본을 복사한 obj2의 a 프로퍼티 빈배열에 값 5을 추가해줬더니 원본 객체 obj에도 똑같이 배열에 값 5가 추가되었어요. 결국 원본을 복사해도 안에 데이터들은 계속 참조가 되고 있다는걸(같은 메모리주소를 바라보고 있다) 확인 할 수 있습니다. 

 

 

📃깊은복사(Deep Copy)

원본은 그대로 유지되고 참조가 완전 끊어진 상태를 깊은 복사라고 합니다.
깊은 복사에도 여러 방법이 있는데 몇개만 알아볼게요

1. Json.parse(JSON.stringify(객체))

const obj = {
    a:[],
    b:1,
    c:2
}
const obj2 = json.parse(json.stringfy(obj))

obj2.a.push(5)

console.log(obj === obj2) //false
console.log(obj.a === obj2.a) //false


위에 얕은복사와 했던거와 다르게 a 프로퍼티의 빈배열에 값을 추가했더니 원본 obj 객체에는 값이 추가되지 않았습니다. 깊은복사는 아예 다른 메모리를 가지고 있구나를 알 수 있고 원본을 그대로 유지하고 싶을경우에 사용 할 수 있겠죠?
하지만 JSON.parse를 사용하면 성능적으로 좋지 못하다고 해요 한 두개 정도 사용할때 사용하면 좋지 않을까 생각합니다

 

2. lodash 라이브러리 사용

JSON.parse의 성능문제도 그렇고 깊은복사의 여러가지 방법이 있지만 lodash 라이브러리를 사용하여 쉽게 깊은복사를 해결한다고 합니다. 아직 전 사용해보지 못했지만 흔히 쓰는 유명한 라이브러리라 이 방법을 사용하면 좋을 듯 합니다

 

이챙(leechaeng)
이챙(leechaeng)

프론트엔드 개발도 하고 뛰기도 하고

'javascript' 카테고리의 관련 글