[JavaScript] 얕은 복사와 깊은 복사

Hyun Jin·2023년 1월 11일
0

JavaScript

목록 보기
13/20

1. 얕은 복사와 깊은 복사란?


  • 한마디로 정리 : 얕은 복사는 객체의 참조값(주소)를 복사하고, 깊은 복사는 객체의 실제 값을 복사합니다.
    얕은 복사는 복사본의 값을 변경할 경우 원본 값도 변경되며, 깊은 복사는 원본 값이 변경되지 않습니다.

들어가기 전에 : 자바스크립트의 데이터 타입(원시타입, 참조타입)

자바스크립트의 데이터 타입에는 원시타입(primitive type), 참조타입(object/reference type) 두가지 타입이 존재합니다.

원시타입에는 string, number, bigint, boolean, undefined, symbol, (null) 7가지 타입이 있습니다.
원시 값을 변수에 할당하면 변수는 메모리(stack 영역)에 실제 값을 저장합니다.

참조타입에는 배열, 객체, 함수 등이 있습니다.
객체를 변수에 할당하면 변수는 메모리(stack 영역)에 참조값(주소값, reference)을 저장합니다. 이 참조값(주소값)은 메모리의 heap 영역에 저장된 데이터를 가리킵니다.

[JavaScript] 7. 원시자료형, 참조 자료형 링크

각 데이터타입을 복사할 때 생기는 일

원시값을 복사할 때 : 원시값을 복사한 값은 또 다른 독립적인 메모리 공간에 할당되기 때문에, 복사 및 값을 수정해도 기존 원시값을 저장한 변수에는 영향을 끼치지 않습니다. 이렇게 실제 값을 복사하는 것은 깊은 복사라고 합니다.
(* 원시값은 얕은 복사, 깊은복사 방법과 상관없이 기본적으로 깊은 복사가 됩니다.)

자료형(참조값)을 복사할 때 : 변수가 객체의 참조(주소)를 가리키고 있기 때문에, 복사된 변수도 동일하게 객체가 저장된 메모리 공간의 참조(주소)를 가리키고 있습니다. 복사 및 값을 수정하면 수정 전/후의 변수가 가리키고 있는 주소값이 같기 때문에 기존 객체를 저장한 변수에 영향을 끼칩니다. 이렇게 객체의 참조값(주소값)을 복사하는 것을 얕은 복사라고 합니다.

일반적으로 복사를 하면 원본 값은 변경되지 않을 것이라고 생각하게 되는데, 자료형의 경우 얕은 복사가 일어나 원본값의 변경이 일어나는 경우가 생길 수 있습니다.
그래서 얕은 복사, 깊은 복사의 방법을 구분해서 사용하는 것이 좋습니다.


2. 얕은 복사 (Shllow Copy)


2-1. 얕은 복사란 ?

객체의 얕은 복사는 복사된 객체의 속성이 원본 객체와 같은 참조값을 가지고 있는 복사를 뜻합니다. 얕은 복사가 되었을 경우 원본 객체와 복사된 객체 중 어느 것을 변경하더라도 다른 객체가 동일하게 변경됩니다. 이것은 의도치 않은 원본 객체나 복사된 객체의 변경을 야기할 수 있으며, 깊은 복사를 사용해서 방지할 수 있습니다.

(+추가 : 얕은 복사는 최상위 레벨의 속성들을 복사한다. 하지만 중첩된 오브젝트들은 (객체 안의 객체) 원본과 복사본 사이에서 공유된다.)

2-2. 얕은 복사 방법

1) Array.prototype.slice()

배열 복사 시 사용.

2) Object.assign()

객체 복사 시 사용.

3) 전개 연산자(spread syntax)

...{}

  • 유의 : 가장 바깥 배열만 복사되기 때문에 가장 바깥 객체를 비교하면 false 이고, 내부 객체를 비교하면 true. 가장 바깥에 있는 외부객체는 참조관계가 없으며, 내부 객체는 참조 관계가 있다.

그외 얕은 복사 방법

Array.prototype.concat(), Array.from(), Object.create()


3. 깊은 복사 (Deep Copy)


3-1. 깊은 복사란 ?

객체의 깊은 복사는 복사된 객체의 속성이 원본 객체와 같은 참조값을 공유하지 않는 복사를 뜻합니다. 깊은 복사가 되었을 경우 원본 객체와 복사된 객체 중 어느 것을 변경하더라도 다른 객체에 영향을 미치지 않습니다. 깊은 복사는 의도치 않은 원본 객체나 복사된 객체의 변경을 방지할 수 있습니다.

3-2. 깊은 복사 방법

1) JSON.stringify() -> JSON.parse()

JSON.stringify() 로 객체를 JSON 문자열으로 변환했다가(이 과정에서 원본 객체와의 참조가 모두 끊어집니다), JSON.parse()로 다시 새로운 Javascript 객체로 변환하는 방법입니다.

  • 장점 : 간단하고 쉬움
  • 단점 : 다른 방법에 비해 비교적 느림, 객체가 finction 일 경우 undefined 로 처리함

2) 재귀함수를 이용한 복사

복잡함

3) Lodash 라이브러리 사용

Lodash의 clonedeep 메소드를 이용하면 Deep Copy가 가능하다.
JSON.parse(JSON.stringify()) 방법의 문제점이였던 함수 복사도 가능하다.

정리

얕은 복사는 원본 객체의 주소값을 복사하여 원본 객체와 복사된 객체가 같은 주소값을 가리키게 되고, 둘 중 하나가 변경될 경우 다른 값도 같이 변경됩니다.
얕은 복사의 방법에는 spread 구문, slice(). assign() 등이 있습니다.

깊은 복사는 원본 객체의 값 자체가 복사되어 다른 주소값을 가지게 됩니다. 그래서 둘 중 하나가 변경되어도 서로 영향을 미치지 않아서 의도치않은 원본 객체나 복사된 객체의 변경을 방지할 수 있고, 상태의 변경을 추적하기 쉽습니다. 원시자료형은 기본적으로 깊은 복사가 됩니다.
깊은 복사의 방법에는 JSON.stringify() -> JSON.parse() 사용, 재귀함수 이용, Lodash 라이브러리 사용 등이 있습니다.

🔗️ 참조사이트 :
MDN - Deep_copy
[JavaScript] 깊은 복사, 얕은 복사
[JavaScript] 깊은복사(Deep Copy)와 얕은복사(Shallow Copy)

profile
새싹 프론트엔드 개발자

0개의 댓글