자바스크립트에서 데이터 유형은 크게 "원시 타입(Primitive Types)"과 "참조 타입(Reference Types)"으로 나눌 수 있다.
원시 타입은 데이터를 단순하게 나타내는 기본적인 데이터 타입으로, 변수에 직접 값을 할당한다. 원시 타입은 불변(Immutable)하며, 메모리에 값 자체가 저장된다.
종류 - 문자열(String) / 숫자(Number) / 불리언(Boolean) / undefined / null / 심볼(Symbol)
참조 타입은 데이터에 대한 참조(Reference)를 저장하고, 변수에는 이 참조(주소)가 할당된다. 참조 타입은 가변(Mutable)하며, 객체, 배열, 함수 등이 이에 해당된다.
종류 - 객체(Object) / 배열(Array) / 함수(function)
참조 타입의 데이터는 복사 시 데이터의 값이 아닌 '값이 저장된 메모리의 주소'가 복사된다.
복사되는 방법에 따라, 참조 타입의 복사는 얕은 복사(Shallow Copy)와 깊은 복사(deep copy)로 나뉜다.
얕은 복사(Shallow copy)는 참조 타입 데이터가 저장한 '메모리 주소 값'을 복사한 것을 의미하며,
깊은 복사(Deep copy)는 새로운 메모리 공간을 확보해 완전히 복사하는 것을 의미한다. 아래에서 자세히 살펴보자.
얕은 복사는 원본 객체 또는 배열의 최상위 수준의 속성(키 또는 인덱스)들만 복사하는 방법이다. 내부에 중첩된 객체나 배열은 동일한 참조(주소)를 유지하게 된다.
const original = { a: 1, b: { c: 2 } }; // 객체 내부에 또 다른 객체가 중첩된 형태
const shallowCopy = Object.assign({}, original); // Object.assign은 얕은 복사 함수
얕은 복사는 성능이 우수하고 구현이 간단하지만, 복잡한 구조의 객체나 배열에는 부적합할 수 있다. 얕은 복사된 값에서 중첩된 객체 / 배열 등이 변경되면 원본 값 또한 변경되기 때문이다.
let original = ['a', 'b', ['c']];
let shallowCopy = origin.slice(); // slice함수의 매개변수를 전달하지 않으면 얕은 복사만 수행
shallowCopy[2].push('d'); // 내부 중첩된 또 다른 배열은 같은 메모리 주소를 사용하고 있기 때문에
console.log(original); //["a", "b", ["c", "d"]]; // 원본까지 바뀌어버림
console.log(shallowCopy); //["a", "b", ["c", "d"]];
깊은 복사는 원본 객체 또는 배열의 모든 수준의 속성을 재귀적으로 복사하는 방법이다.
내부 객체나 배열도 모두 복사되어 새로운 참조를 가지게 되며, 새로운 값으로 재탄생된다고 보면 된다.
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original)); // 문자열화 후 다시 객체화
단, JSON.stringify(), parse()
방법은 특별한 타입(함수, undefined, Symbol, Date 등)를 다루지 못할 수 있다. 또한 깊은 복사는 모든 deps의 복사를 수행하므로, 얕은 복사에 비해 성능상의 부담이 있을 수 있다.
얕은 복사와 깊은 복사는 각각의 상황에 맞게 선택되어야 하며, 복사하려는 데이터의 구조와 요구 사항을 고려하여 적절한 방법을 선택하는 것이 중요하다. 또한 얕은 복사와 깊은 복사의 종류에는 여러가지가 있다. 다음 포스트에서 자세히 살펴보자.