얕은 복사는 객체의 참조값(주소 값)을 복사하고, 깊은 복사는 객체의 실제 값을 복사한다.
자바스크립트에서 값은 원시값과 참조값 두 가지 데이터 타입의 값이 존재한다.
자바스크립트에서 원시 타입(primitive type)의 값은 새로운 메모리 공간에 독립적인 값을 저장하기 때문에 깊은 복사가 되고 참조 타입(reference type)값은 얕은 복사가 된다. 원시 타입과 참조 타입의 가장 큰 차이점은 원본이 바뀌면 참조 타입은 복사본도 같이 변경되지만, 원시 타입은 변경되지 않는다는 점이 큰 차이점이다.
// 원시 타입의 깊은 복사
let a = '원본 데이터';
let b = a;
a = '수정 데이터';
console.log(a); // '수정 데이터'
console.log(b); // '원본 데이터'
원시 타입은 복사 시 값 자체를 담은 독립적인 메모리를 생성하기 때문에 a가 재할당 되더라도 b에는 아무런 영향을 미치지 않는다.
// 참조 타입의 얕은 복사
let a = {name:'원본 데이터'};
let b = a;
a.name = '수정 데이터';
console.log(a); // '수정 데이터'
console.log(b); // '수정 데이터'
원시 타입과 달리 참조 타입인 오브젝트는 새로운 값으로 변수 값을 재할당 하자 복사된 변숫값도 같이 변경되는 것을 확인할 수 있다. 즉, 데이터가 그대로 하나 더 생성된 것이 아닌 해당 데이터의 메모리 주소를 전달하게 돼서, 결국 한 데이터를 공유하게 되는 걸 알 수 있다.
얕은 복사란 객체를 복사할 때 기존 값과 복사된 값이 같은 참조를 가리키고 있는 것을 말한다. 객체 안에 객체가 있을 경우 한 개의 객체라도 기존 변수의 객체를 참조하고 있다면 이를 얕은 복사라고 한다.
얕은 복사 방법의 대표적인 예라고 할 수 있다. start부터 end 인덱스까지 기존 배열에서 추출하여 새로운 배열을 리턴하는 메소드이다. 만약 start와 end를 설정하지 않는다면, 기존 배열을 전체 얕은 복사한다.
const original = ['a',2,true,4,"hi"];
const copy = original.slice();
console.log(JSON.stringify(original) === JSON.stringify(copy)); // true
copy.push(10);
console.log(JSON.stringify(original) === JSON.stringify(copy)); // false
console.log(original); // [ 'a', 2, true, 4, 'hi' ]
console.log(copy); // [ 'a', 2, true, 4, 'hi', 10 ]
기존 배열에는 영향을 끼치지 않아서 깊은 복사로 보일 수 있지만, 원시값을 저장한 1차원 배열일 뿐이다. 원시값은 기본적으로 깊은 복사이다. Slice() 메소드는 기본적으로 얕은 복사를 수행한다.