JavaScript | 얕은 복사 vs 깊은 복사

권지현·2022년 1월 21일
0
post-thumbnail

자바스크립트에서 변수를 다루다보면 값을 재할당하거나 기존 값에서 일부만 추출하거나 여러 방식으로 데이터를 다루게 될 것이다. 변수가 원시값 이라면 값이 변하지 않기 때문에 복사해도 원래 값에 영향을 주지 않겠지만 코드가 긴 상태에서 참조값을 복사한다면 기존 값을 찾기 힘들고 어떻게 값이 변했는 지도 찾기 쉽지 않을 것이다. 그래서 참조값을 다루기위해서는 얕은 복사와 깊은 복사에 대해 알아둬야한다.

⚙️ 값의 특징과 함께 복사에 관한 코드를 간단히 살펴보자.

기존에 이런식으로 배열을 복사한다면,

let A = "hello"; 
let B = A;
console.log(A); // "hello"
console.log(B); // "hello"

B = "World"; 

console.log(A); // "hello"
console.log(B); // "World"

변수 A는 원시값을 가지기 때문에 기존 값을 복사한 후 변수 B의 값을 재할당해도 원본은 변하지 않는다.
하지만 참조값을 가진 변수의 경우로 본다면 얕은 복사로 원본 값까지 변하게 되는 것이다.

💡 잠깐 TIP !!

원시 자료형
- 고정된 저장 공간을 차지하는 데이터
- 객체가 아니면서 method를 가지지 않는 타입
: Number , Symbol, String , Boolean , Null , Undefined ...
- 값 자체에 대한 변경이 불가능(immutable)하지만, 변수에 다른 데이터를 할당할 수는 있다.

참조 자료형
- 원시 자료형이 아닌 모든 데이터 : 배열, 객체, 함수 등
- HEAP이라는 특별한 저장 공간을 사용하고 이 저장 공간이 유동적으로 늘어나며, 여러 개의 데이터를 가지고 있다.
- 데이터가 위치한 주소가 변수에 저장되는 방식으로 변수의 주소를 참조한다.

📚 얕은 복사

: 사본을 만들어내지 않고 원본을 참조하도록 데이터 값을 가져오는 것

let arr = [1,2,3]

let a = arr

a[0] = 4

console.log(a)  //결과 : [4,2,3]
console.log(arr) //결과 : [4,2,3]

이렇게 참조값을 가진 변수 a만 변화를 주었지만 a는 arr 라는 배열의 값을 가져온 것이기 때문에 원본 값인 arr의 값도 변하게 된다.

🤷🏻‍♀️ 그렇다면 배열에서 복사는 어떻게 할까.

배열에서 복사한 새로운 변수가 원본에 영향이 가지 않게 하기 위해 " 스프레드 연산자 " 를 사용한다. 엄밀히 말하면 복사가 아니라 원본 값을 받은 새로운 객체를 만들어내는 것.

let num = [1,2,3]
let number = num

number.push(3) // 결과 : num과 number 모두 [1,2,3,3]

//스프레드 사용 시,
let num = [1,2,3]
let number = [...num]

number.push(3)
//결과 : num = [1,2,3]
//number = [1,2,3,3]

이렇게 복사를 하면 배열 값의 주소를 참조하는 게 아니라 새로운 객체를 다시 만들어내 원본에 영향이 없게 복사가 가능하다.

🙅🏻‍♀️ 스프레드 사용시 주의 사항 !

객체를 복사할 경우 1차 복사만 가능하기 때문에 객체 내에 객체로 구성된 데이터를 변경할 경우 원본까지 변경된다.
그래서 깊은 복사를 하기 위해 객체를 문자열로, 문자열을 다시 객체로 바꿔주는 작업이 필요하다.

🔏 깊은 복사

: 완벽하게 원본과 사본을 나눠 복사하는 방법

let arr1 = [1, 2, 3, 4];
let arr2 = arr1.slice();

console.log(arr1); //결과 : [1, 2, 3, 4]
console.log(arr2); //결과 : [1, 2, 3, 4]

arr2[0] = 0;

console.log(arr1); //결과 : [1, 2, 3, 4]
console.log(arr2); //결과 : [0, 2, 3, 4]
console.log(arr1 === arr2); //false

그래서 참조값을 가지는 변수의 경우 메서드를 활용해 깊은 복사 즉, 새로운 배열을 만들어서 기존 배열에 영향이 가지 않게끔 해주는 것이다.

객체에서는 -> 문자열 -> 객체의 과정이 필요하다.
아래 사진처럼 profile이라는 객체를 profile2로 복사하고 profile2를 변경해도 원본은 영향이 가지 않는다.

  • JSON.parse() - 객체를 문자열로 변경
  • JSON.stringify() - 문자열을 객체로 바꾸는 방법

하지만 이 과정도 코드로 옮기게 되면 로직이 진행되는 데 어느 정도의 시간이 걸리기때문에 이미 만들어진 라이브러리( " Lodash " )를 이용하는 것을 추천한다.

💡 TIP !
이해를 돕기 위한 사이트 👉🏻 MDN , 개발 관련 블로그
🙊 블로그는 쉽게 정리를 잘 해주셔서 이해하는데 큰 도움이 되었다.

profile
FE 개발자 성장 기록 👩🏻‍💻

0개의 댓글