JavaScript 데이터 타입 — 원시값과 참조값의 메모리 차이
자바스크립트의 데이터 타입은 크게 원시값(Primitive) 과 참조값(Reference) 으로 나뉩니다. 면접에서 "원시값과 참조값의 차이"를 물어보면, 단순히 목록을 나열하는 것보다 메모리에 어떻게 저장되는지 를 설명할 수 있어야 합니다.
원시 타입 7가지
자바스크립트의 원시 타입은 총 7개입니다.
// 원시 타입 목록
const str = "hello"; // string
const num = 42; // number
const big = 9007199254740991n; // bigint
const bool = true; // boolean
const undef = undefined; // undefined
const nul = null; // null
const sym = Symbol("id"); // symbol
원시값의 핵심 특징은 불변(immutable) 이라는 점입니다. 문자열을 "변경"하는 것처럼 보여도 실제로는 새로운 문자열이 만들어집니다.
let greeting = "hello";
greeting = "world"; // "hello"가 변경된 게 아니라, 새 문자열 "world"가 생성됨
참조 타입
원시 타입이 아닌 모든 것은 참조 타입입니다.
const obj = { name: "심정훈" }; // 객체
const arr = [1, 2, 3]; // 배열 (사실 객체)
const fn = () => {}; // 함수 (사실 객체)
const date = new Date(); // Date (사실 객체)
메모리 저장 방식의 차이
면접에서 가장 자주 물어보는 포인트입니다.
원시값 — 스택에 값 자체를 저장
let a = 10;
let b = a; // 값이 복사됨
b = 20;
console.log(a); // 10 — a는 영향 없음
b = a를 실행하면 a의 값 10이 복사 되어 b에 저장됩니다. 이후 b를 변경해도 a에는 영향이 없습니다.
참조값 — 힙에 데이터, 스택에 주소를 저장
let obj1 = { name: "홍길동" };
let obj2 = obj1; // 주소가 복사됨
obj2.name = "이순신";
console.log(obj1.name); // "이순신" — obj1도 같이 변경됨!
obj2 = obj1은 객체를 복사한 게 아니라 같은 힙 메모리 주소 를 공유합니다. 그래서 하나를 수정하면 다른 쪽에도 반영됩니다.
비교 연산의 차이
// 원시값: 값으로 비교
"hello" === "hello" // true
// 참조값: 주소로 비교
{ name: "a" } === { name: "a" } // false — 서로 다른 객체
면접에서 "빈 객체끼리 ===로 비교하면 왜 false인가요?"라는 질문이 나올 수 있습니다. 답은 참조값은 메모리 주소를 비교 하기 때문입니다.
함수 인자 전달
자바스크립트는 항상 값에 의한 전달(pass by value) 입니다. 다만 참조값의 경우 "값"이 메모리 주소이므로 마치 참조 전달처럼 보입니다.
// 원시값 전달 — 외부 변수 변경 불가
function changeValue(x) {
x = 100;
}
let num = 10;
changeValue(num);
console.log(num); // 10
// 참조값 전달 — 내부 프로퍼티 변경 가능
function changeName(obj) {
obj.name = "변경됨";
}
let person = { name: "원본" };
changeName(person);
console.log(person.name); // "변경됨"
// 하지만 재할당은 외부에 영향 없음
function replaceObj(obj) {
obj = { name: "새 객체" }; // 새 주소를 가리킴
}
replaceObj(person);
console.log(person.name); // "변경됨" — 재할당은 외부에 영향 없음
typeof 연산자의 함정
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" ← 유명한 버그!
typeof {} // "object"
typeof [] // "object" ← 배열도 object
typeof function(){} // "function"
typeof null === "object"는 자바스크립트 초기 구현의 버그인데, 하위 호환성 때문에 수정되지 않았습니다. 배열인지 확인하려면 Array.isArray()를 사용해야 합니다.
깊은 복사 vs 얕은 복사
참조값을 안전하게 복사하려면 깊은 복사가 필요합니다.
const original = { a: 1, nested: { b: 2 } };
// 얕은 복사 — 1단계만 복사
const shallow = { ...original };
shallow.nested.b = 999;
console.log(original.nested.b); // 999 — 중첩 객체는 공유됨
// 깊은 복사 — structuredClone (모던 브라우저)
const deep = structuredClone(original);
deep.nested.b = 0;
console.log(original.nested.b); // 999 — 영향 없음
면접 포인트 정리
| 구분 | 원시값 | 참조값 |
|---|---|---|
| 저장 위치 | 스택 | 힙 (스택에 주소 저장) |
| 복사 | 값 복사 | 주소 복사 (얕은 복사) |
| 비교 | 값 비교 | 주소 비교 |
| 불변성 | 불변 | 가변 |
| typeof | 정확함 (null 제외) | "object" |
**기억하기 **: 원시값은 "값 자체"를 다루고, 참조값은 "주소"를 다룹니다. 면접에서 이 차이를 메모리 관점으로 설명할 수 있으면 기본기가 탄탄하다는 인상을 줄 수 있습니다.