얕은 복사와 깊은 복사에 대해서 알아보자 🤲
원시 자료형
을 할당한 변수를 다른 변수에 할당하면 값 자체의 복사가 일어난다.
참조 자료형
은 임의의 저장공간에 값을 저장하고 그 저장공간을 참조하는 주소를 메모리에 저장하기 떄문에
다른 변수에 할당할 경우 값 자체가 아닌 메모리에 저장되어 있는 주소가 복사된다.
즉 둘 중 하나를 변경하면 변수가 참조하고 있는 주소에 있는 값이 변동되기때문에 다른 하나에도 영향을 끼친다.
배열과 객체 같은 참조 자료형을 복사하여 주소 값이 변동되지않게 하는 방법이 있다.
원시 자료형이 할당된 변수를 다른 변수에 할당하면 값 자체의 복사
참조 자료형의 할당된 변수를 다른 변수에 할당하면 주소가 복사되어 원본과 복사본이 같은 주소를 참조한다.
참조 자료형의 주소값을 복사한 변수에 요소를 추가하면 같은 주소를 참조하고 있는 원본에도 영향을 미친다.
참조 자료형이 저장된 변수르 다른 변수에 할당할 경우, 두 변수는 같은 주소를 참조하고 있을 뿐 값 자체가 복사되었다고 볼 수는 없다.
배열 복사하기
let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
위 코드와 같이 slice 매서드에 빈 값을 집어넣게 되면 새롭게 생성 된 배열을 볼 수 있다.
동등연산자로 확인해볼때 기존배열과 같지 않다라고 나온다. 주소가 다르기 때문에 배열의 값을 수정 , 삭제해도
영향을 받지 않는다.
…
을 이용해 배열이 할당된 변수명 앞에 붙여주면 배열의 복사가 가능하다.
let arr = [0, 1, 2, 3];
let copiedArr = [...arr];
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
배열을 복사해 새로운 주소로 할당되었기 때문에 값을 서로가 영향을 받지않는걸 확인할 수 있다.
참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것은 깊은 복사(deep copy)라고 한다.
하지만 JavaScript 내부적으로 깊은 복사를 수행할 수 있는 방법이 없기에
다른 문법을 응용하여 깊은 복사와 같은 결과물을 만들어 낼 수 있다.
JSON.stringify()
와 JSON.parse()
JSON.stringify()
는 참조 자료형을 문자열 형태로 변환하여 반환하고
JSON.parse()
는 문자열의 형태를 객체로 변환하여 반환한다.
const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // falseㄴ
먼저 중첩된 참조 자료형을 JSON.stringify()를 이용하여 문자열의 형태로 변환하고,
반환된 값에 다시 JSON.parse()를 사용하면 깊은 복사와 같은 결과물을 반환한다.
이 방법 또한 깊은 복사의 예외 조건이 있는데 대표적인 예로는 참조 자료형 중에 함수가 포함되어 있을때
null
로 바뀌게 된다. 따라서 완전한 깊은 복사 방법이라고 보기는 어렵다
const arr = [1, 2, [3, function(){ console.log('hello world')}]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, function(){ console.log('hello world')}]]
console.log(copiedArr); // [1, 2, [3, null]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
완전한 깊은 복사를 반드시 해야하는 경우, node.js
환경에서 외부 라이브러리인 lodash
, 또는 ramda
를 설치해 사용하면 된다.
slice()
메서드 또는 spread syntax 등의 방법으로 복사할 수 있다.Object.assign()
또는 spread syntax 등의 방법으로 복사할 수 있다.JSON.stringify()
와 JSON.parse()
를 사용하는 방법이 있지만, 예외의 케이스가 존재한다. (참조 자료형 내부에 함수가 있는 경우)