자바스크립트에서 변수를 다루다보면 값을 재할당하거나 기존 값에서 일부만 추출하거나 여러 방식으로 데이터를 다루게 될 것이다. 변수가 원시값 이라면 값이 변하지 않기 때문에 복사해도 원래 값에 영향을 주지 않겠지만 코드가 긴 상태에서 참조값을 복사한다면 기존 값을 찾기 힘들고 어떻게 값이 변했는 지도 찾기 쉽지 않을 것이다. 그래서 참조값을 다루기위해서는 얕은 복사와 깊은 복사에 대해 알아둬야한다.
기존에 이런식으로 배열을 복사한다면,
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를 변경해도 원본은 영향이 가지 않는다.
하지만 이 과정도 코드로 옮기게 되면 로직이 진행되는 데 어느 정도의 시간이 걸리기때문에 이미 만들어진 라이브러리( " Lodash " )를 이용하는 것을 추천한다.
💡 TIP !
이해를 돕기 위한 사이트 👉🏻 MDN , 개발 관련 블로그
🙊 블로그는 쉽게 정리를 잘 해주셔서 이해하는데 큰 도움이 되었다.