JS 자료형 7가지 — typeof 와 헷갈리는 null
primitive 7개와 typeof 사용법, 영원한 함정 null vs undefined.
JS 에는 두 종류의 자료형이 있습니다 — primitive(원시) 7개와 object(객체) 1종류. 객체는 10편에서 자세히 다루고, 이번 편은 primitive 7개를 정확히 정리합니다. typeof 라는 작은 연산자 하나로 어떤 타입인지 확인할 수 있고, null vs undefined 의 영원한 함정도 풀어봅니다.
primitive 7개 — 한 표
| 자료형 | 예시 | typeof 결과 |
|---|---|---|
| number | 42, 3.14, Infinity, NaN | "number" |
| string | "hi", `temp ${x}` | "string" |
| boolean | true, false | "boolean" |
| undefined | 초기화 안 됨 | "undefined" |
| null | "비어있음" 명시 | "object" ← 함정! |
| symbol | Symbol("key") | "symbol" |
| bigint | 9007199254740993n | "bigint" |
number — 하나의 타입에 다 들어있다
console.log(typeof 42); // "number"
console.log(typeof 3.14); // "number"
console.log(typeof Infinity); // "number"
console.log(typeof NaN); // "number" ← Not-a-Number 인데 number
// 안전 정수 한계
Number.MAX_SAFE_INTEGER // 9_007_199_254_740_991 (2^53 - 1)
Number.MAX_SAFE_INTEGER + 1 // 9007199254740992 (OK)
Number.MAX_SAFE_INTEGER + 2 // 9007199254740992 ← !! 정밀도 손실
// 그래서 등장한 게 bigint
9007199254740993n + 1n // 9007199254740994n (정확)
NaN 의 함정. NaN === NaN 은 false입니다. NaN 인지 확인하려면 Number.isNaN(x) 를 쓰세요. 글로벌 isNaN() 은 문자열을 number 로 강제 변환해서 의도와 다르게 동작합니다.
string — 세 가지 따옴표
const s1 = "쌍따옴표";
const s2 = '홑따옴표';
const s3 = `백틱 — 줄바꿈
가능하고 ${변수} 보간도 됨`;
s3.length // 글자 수
s3.toUpperCase() // 대문자
s3.includes("백") // true/false
s3.replace("백", "B") // "B틱..."
s3.split(",") // 배열
`${"x".repeat(5)}` // "xxxxx"
거의 항상 백틱(`) 을 권장합니다. 변수 보간이 되고 줄바꿈도 자유로워서, 두 가지 따옴표 사이의 종교 전쟁이 사실상 끝났어요. 11편(문자열 메서드) 에서 더 깊게.
null vs undefined — 형제 같은 사이
let a; // 선언만 하고 값 없음 → undefined
let b = null; // 명시적으로 "비어있음" 표시
typeof a // "undefined"
typeof b // "object" ← 역사적 버그, 못 고침
a == null // true (== 는 둘 다 null 취급)
a === null // false (=== 는 엄격)
b === null // true
실무 관례:
- undefined — 시스템(JS 엔진) 이 만든다. "아직 값 없음" 의 자연 상태.
- null — 사람이 만든다. "여기에 의도적으로 비워뒀다" 의 표시.
둘 다 "값 없음" 이지만 의도가 다릅니다. API 응답에서 { "phone": null } 은 "전화번호가 없음을 알려준다", { }(phone 필드 자체 없음) 은 "전화번호 정보가 안 왔다" — 이 차이가 종종 중요합니다.
nullish 단축 연산자 ??. x ?? "기본값" 은 x 가 null/undefined 일 때만 기본값을 씁니다. 옛날엔 x || "기본값" 을 썼는데, 이건 0·""·false 까지 "비어있다" 로 봐서 의도와 다른 결과가 나옵니다. 새 코드는 ?? 권장.
symbol·bigint — "있다는 것만 알아두자"
// symbol — 절대 충돌하지 않는 고유 키
const KEY = Symbol("user");
const obj = { [KEY]: "준성" };
obj[KEY] // "준성"
obj["KEY"] // undefined ← symbol 은 일반 키로 못 옴
// bigint — 정밀도 무한 정수 (n 접미사)
const big = 12345678901234567890n;
big * 2n // 24691357802469135780n
big + 1 // ❌ bigint 와 number 는 직접 못 섞음
big + 1n // OK
둘 다 입문 단계에서는 거의 안 씁니다. symbol 은 React 의 일부 내부 키나 라이브러리 내부 약속에서 가끔 보고, bigint 는 암호학·금융 등 큰 정수가 필요할 때만. 이름만 익혀두세요.
5편 — 연산자와 비교 (===)
산술·비교·논리 연산자, 그리고 왜 항상 === 를 써야 하는지(== 의 타입 강제 변환 함정).
이전: 3편 변수 · 현재: 4편 (입문) · 다음 → 5편 연산자 · 진행: 4/26