들어가며

개발하며 아티클을 읽다보면 한번 쯤은 보게되는 단어가 있다.
깊은 복사 (Deep Copy), 얕은 복사 (Shallow Copy) 가 그 주인공이다.

이거 이름만 봐도 궁금증이 생기지 않는가??
아니 복사면 복사지 대체 깊은 복사 는 뭐고 얕은 복사 는 뭘 뜻하는걸까?

이번에는 이 두개를 한번 알아보도록 하자.


사전지식

사전 지식.......?? 😩

깊은 복사 와 얕은 복사를 알기 전에 우선 몇 가지 사전지식이 필요하다.
이걸 모르면 반 쪽 짜리 지식이라고 할 수 있다.

(그리고 모르면 자꾸 까먹으니 알아야 한다)


데이터의 저장

데이터 저장?? 이건 왜 알아야 하는거죠?? 🙄

자 한번 생각해보자.
어디에 어떻게 저장되는지도 모르는데, 그걸 어떻게 복사하는지 완벽히 이해할 수 있을까?

당연히 불가능하다. 그건 그냥 면접 답변 용으로 외우는 정도이지, 조금만 깊게 가면 알 수 없다.

때문에 Javascript에서 데이터가 어떻게 저장되었는지 부터 알아보도록 하자.
(굉장히 러프하게 작성한 내용이므로, 자세한 내용은 구글링을 통해 공부해보자)

메모리에 저장

Javascript 에서는 변수에 값 을 할당하는 식으로 코드를 작성한다.

let newValue = 100;

근데 이 값은 어디에 어떻게 저장되는 걸까?
그건 바로 메모리 영역에 저장을 하게된다.

쉽게 그림으로 이해하자면 아래와 같다.

(실제로 메모리 주소가 이렇게 잡히지는 않는다. 참고용으로 이렇다~ 정도로 생각해주자)

메모리 주소 1000에 변수의 이름이 저장되었고, 그 변수의 데이터는 메모리 주소 4001에 있다고 되어있다.
이 때 메모리주소 4001에 가보면 아까 우리가 할당 한 데이터 100을 보게 된다.

그럼 객체(Object)의 저장 같은 경우는 어떻게 될까?

let newObject = {
  name:'himprover',
  money:0,
}

대략 이런식으로 저장이 된다.
여기서 핵심은 데이터는 메모리 상에 저장되고, 그 주소값을 저장 한다는 점이다.



이제 본론으로

여기까지 읽었다면 눈치 빠른 사람은 이제 느낌이 좀 올거다.

그럼 대충...머... 복사할때 주소값 머 그런거에 따라서... 깊고 얕은 그런건가...? 😏

이런 의문이 들었다면 같이 얕은복사, 깊은복사를 정복하러 가보자!


원시값, 참조값의 복사

엥??? 갑자기 원시값 참조값이요? 😫

Javascript에서 값은 원시값과 참조값으로 나누어 진다.

원시값 종류

  • Number (숫자)
  • String (문자)
  • Boolean (true/false)
  • NULL (비어있음)
  • undefined (정의안됨)
  • Symbol (심볼)

참조값 종류

  • Object (객체)

Symbol (심볼)

2022.12.05. 수정, Symbol은 원시값입니다! (feedback: gomiseki님 감사합니다.)

어려우면 그냥 간단하게 생각해서 Object 아니면 다 원시값이라고 생각해보자.

아무튼 원시값과 참조값의 경우 복사하는 과정에서 차이점이 나타난다.


원시값의 복사

원시값을 복사하면 주소값이 아닌 데이터 자체를 복사한다.
이게 무슨말인지 그림을 보며 이해해보자.

let first = 'hi'
let second = first;

그림을 보면 second가 바라보는 메모리 주소는 first의 4001이 아닌 4002에 새로 만들어주었다.

아니 당연한거 아닌가요? 이거 뭐 당연한 얘기 같은데... 😑

과연 그럴까? 이번엔 객체의 복사를 알아보자.


참조값의 복사

얕은 복사

참조값을 복사하면 기본적으로 얕은 복사로 진행이 된다.
여기서 얕은 복사란 데이터 자체가 아닌 메모리 주소 만 복사한다는 것이다.

이것도 그림을 통해 알아보자.

let student1 = {
  name:'himprover',
  money:0,
}
let student2 = student1;

어라???? 🤨

원시값의 복사와 달리 데이터를 새로 저장하지 않고 student1의 메모리 주소 4001을 그대로 가져와 사용했다.

즉 얕은 복사란 데이터를 복사하는 것이 아닌, 데이터의 메모리 주소만 복사하는 것을 뜻한다.


깊은 복사

얕은 복사가 메모리 주소를 복사하는 거니까, 깊은 복사는 데이터를 복사하는 거겠네요 😆

맞다. 깊은 복사는 메모리를 복사하는 것이 아닌 원시값 복사 처럼 데이터를 복사하는 것이다.



근데 이 두개 왜 나눠짐?

이쯤 되면 이런 의문이 들 것이다.
원시값 처럼 데이터를 복사하면 되는데 굳이 얕은 복사를 만들어 기본 설정으로 해 둔 이유는 뭘까?
(왜 굳이 우리 하나 더 공부하게 했을까)

핵심만 말하자면 돈 때문이다.


생각해보자, 실제 서비스의 코드에서 객체는 아까 그 예제처럼 크기가 작지 않다.
만약 큰 객체를 원시값처럼 복사하면 속도, 저장소 크기 두 가지의 문제가 생긴다.

속도 - 데이터가 많으니 복사하는 데 시간이 오래걸릴 거고,
저장소 크기 - 데이터를 다 다시 저장하니 저장소를 더 쓰게된다.

그럼 결국 장비의 성능을 올려야 하고 그건 돈이 더 들게 된다.
(깊은 복사 때문에 램 사고 CPU 사면 좀 억울할거다)

이 때문에 최대한 최적화해서 사용하기 위해 얕은 복사를 만들어 낸 것이다.


얕은 복사의 문제점

조금 전 얕은 복사의 탄생 이유에 대해 설명을 했다.
그럼 그 다음은 뭘까?

당연히 깊은 복사의 탄생 이유이다.
얕은 복사가 완벽하면 깊은 복사라는 것 자체가 나올리가 없지 않은가?

지금까지 공부한 내용으로 얕은 복사의 문제점이 뭘지 한번 생각해보자.

문제점은 바로 같은 주소를 공유한다는 점

같은 주소를 사용하게 되면, 어느 한 객체에서 값을 수정했을 때 다른 객체도 같이 수정되게 된다.

왜냐? 같은 주소를 사용하고 있으니까.

예를들어 학생1의 형식만 가져와서 학생2를 만든 다음에, 학생2의 이름에 맞게 값을 변경해주면 학생1의 값도 변경되게 된다.

let student1 = {
  name:'himprover'
}
let student2 = student1;
student2.name = 'joohyun';

(궁금하면 한번 개발자도구 console에 똑같이 쳐보자)


깊은 복사 하는 법

아하 깊은 복사는 그래서 있군요... 그럼 어떻게 하나요? 😀

링크참고 :)



정리

이제 얕은 복사, 깊은 복사 얘기가 나왔을 때 헷갈리지 말고 당당하게 말할 수 있다!
얕은 복사는 주소만 깔짝 복사하는 거고 깊은 복사는 데이터 자체를 복사하는 거다.

이 내용에서 핵심은 데이터가 어떻게 저장되는지, 왜 얕은복사, 깊은복사가 나누어졌는지 이 두가지라고 할 수 있다.

한번 직접 Javascript로 만들어보며 완벽히 이해해보자!


  • Javascript에서 데이터는 메모리 상에 저장되고, 주소로써 표현함
  • 얕은 복사는 데이터의 메모리 주소만 복사함
  • 깊은 복사는 데이터 자체를 복사해서 새로 저장함
  • 객체를 복사할때는 얕은 복사가 기본적으로 진행 됨
  • 얕은 복사, 깊은 복사 는 각각 필요한 곳에 맞게 잘 사용해야 함

+ 읽어주셔서 감사합니다.
+ 오타, 내용 지적, 피드백을 환영합니다. 많이 해주실 수록 제 성장의 밑거름이 됩니다.
profile
반갑습니다. 프론트엔드 개발자 황주현 입니다. 🤗

2개의 댓글

comment-user-thumbnail
2022년 12월 2일

안녕하세요, 원시 값 자료를 찾다가 보게되었는데 혹시 symbol을 참조형으로 소개하는 레퍼런스가 있나요?
MDN에서는 원시값으로 소개하고있어서요! 글 잘 봤습니다~

1개의 답글