개발하며 아티클을 읽다보면 한번 쯤은 보게되는 단어가 있다.
깊은 복사 (Deep Copy)
, 얕은 복사 (Shallow Copy)
가 그 주인공이다.
이거 이름만 봐도 궁금증이 생기지 않는가??
아니 복사면 복사지 대체 깊은 복사
는 뭐고 얕은 복사
는 뭘 뜻하는걸까?
이번에는 이 두개를 한번 알아보도록 하자.
사전 지식.......?? 😩
깊은 복사
와 얕은 복사
를 알기 전에 우선 몇 가지 사전지식이 필요하다.
이걸 모르면 반 쪽 짜리 지식이라고 할 수 있다.
(그리고 모르면 자꾸 까먹으니 알아야 한다)
데이터 저장?? 이건 왜 알아야 하는거죠?? 🙄
자 한번 생각해보자.
어디에 어떻게 저장되는지도 모르는데, 그걸 어떻게 복사하는지 완벽히 이해할 수 있을까?
당연히 불가능하다. 그건 그냥 면접 답변 용으로 외우는 정도이지, 조금만 깊게 가면 알 수 없다.
때문에 Javascript
에서 데이터가 어떻게 저장되었는지 부터 알아보도록 하자.
(굉장히 러프하게 작성한 내용이므로, 자세한 내용은 구글링을 통해 공부해보자)
Javascript
에서는 변수에 값 을 할당하는 식으로 코드를 작성한다.
let newValue = 100;
근데 이 값은 어디에 어떻게 저장되는 걸까?
그건 바로 메모리 영역에 저장을 하게된다.
쉽게 그림으로 이해하자면 아래와 같다.
(실제로 메모리 주소가 이렇게 잡히지는 않는다. 참고용으로 이렇다~ 정도로 생각해주자)
메모리 주소 1000에 변수의 이름이 저장되었고, 그 변수의 데이터는 메모리 주소 4001에 있다고 되어있다.
이 때 메모리주소 4001에 가보면 아까 우리가 할당 한 데이터 100을 보게 된다.
그럼 객체(Object
)의 저장 같은 경우는 어떻게 될까?
let newObject = {
name:'himprover',
money:0,
}
대략 이런식으로 저장이 된다.
여기서 핵심은 데이터는 메모리 상에 저장되고, 그 주소값을 저장 한다는 점이다.
여기까지 읽었다면 눈치 빠른 사람은 이제 느낌이 좀 올거다.
그럼 대충...머... 복사할때 주소값 머 그런거에 따라서... 깊고 얕은 그런건가...? 😏
이런 의문이 들었다면 같이 얕은복사
, 깊은복사
를 정복하러 가보자!
엥??? 갑자기 원시값 참조값이요? 😫
Javascript
에서 값은 원시값과 참조값으로 나누어 진다.
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로 만들어보며 완벽히 이해해보자!
+ 읽어주셔서 감사합니다.
+ 오타, 내용 지적, 피드백을 환영합니다. 많이 해주실 수록 제 성장의 밑거름이 됩니다.
안녕하세요, 원시 값 자료를 찾다가 보게되었는데 혹시 symbol을 참조형으로 소개하는 레퍼런스가 있나요?
MDN에서는 원시값으로 소개하고있어서요! 글 잘 봤습니다~