원시 타입 7가지 — JavaScript의 기본 데이터

JavaScript의 7가지 원시 타입(number, string, boolean, null, undefined, Symbol, BigInt)의 특징과 typeof 동작, 원시 타입과 참조 타입의 차이를 설명합니다.

· 7 min read · PALDYN Team

지난 글에서 letconst의 Temporal Dead Zone이 왜 존재하는지, 그리고 어떤 상황에서 ReferenceError가 발생하는지 살펴봤습니다. 이번 글에서는 JavaScript의 자료형 체계의 기초인 **원시 타입(primitive type)**을 정리합니다.

원시 타입이란

JavaScript에서 모든 값은 원시 타입이거나 **참조 타입(객체)**입니다. 원시 타입은 가장 기본적인 데이터 형태로, **불변(immutable)**합니다. 값 자체를 직접 변경할 수 없고, 변수에 새 값을 할당할 뿐입니다.

let str = "hello";
str.toUpperCase();     // "HELLO" — 원본을 바꾸지 않음
console.log(str);      // "hello" — 그대로

str = str.toUpperCase(); // 새 문자열을 변수에 재할당
console.log(str);        // "HELLO"

원시 타입 7가지

1. number

JavaScript에는 정수와 실수를 구분하는 타입이 없습니다. 모두 IEEE 754 배정밀도 부동소수점 형식으로 저장됩니다.

typeof 42;        // "number"
typeof 3.14;      // "number"
typeof -0;        // "number"
typeof NaN;       // "number" — Not a Number도 number 타입!
typeof Infinity;  // "number"

// 정수 범위
Number.MAX_SAFE_INTEGER;  // 9007199254740991 (2^53 - 1)
Number.MIN_SAFE_INTEGER;  // -9007199254740991

// 특수 값
isNaN(NaN);    // true
isFinite(Infinity); // false

NaN은 “숫자가 아니다”라는 의미지만 typeof NaN === "number"라는 역설적 결과를 줍니다. 또 NaN !== NaNtrue이므로 ===로는 NaN을 검사할 수 없습니다. Number.isNaN() 또는 Object.is(x, NaN)을 사용하세요.

2. string

문자열은 UTF-16 코드 유닛의 시퀀스입니다. 작은 따옴표, 큰 따옴표, 백틱(템플릿 리터럴) 세 가지로 만들 수 있습니다.

const s1 = 'single';
const s2 = "double";
const s3 = `template ${1 + 1}`; // "template 2"

// 문자열은 불변
const str = "hello";
str[0] = "H"; // 조용히 무시됨 (strict: TypeError)
console.log(str); // "hello" — 바뀌지 않음

// 연결은 새 문자열 생성
const result = str + " world"; // "hello world"

3. boolean

truefalse 두 값만 갖습니다. 조건문, 논리 연산자, 비교 연산자의 결과로 자주 등장합니다.

typeof true;  // "boolean"
typeof false; // "boolean"

// falsy 값들 — boolean 변환 시 false가 되는 값
Boolean(0);           // false
Boolean("");          // false
Boolean(null);        // false
Boolean(undefined);   // false
Boolean(NaN);         // false
Boolean(false);       // false
// 위 6개 외의 모든 값은 truthy

4. null

null의도적으로 값이 없음을 나타냅니다. 프로그래머가 명시적으로 “여기에는 아무것도 없다”고 선언할 때 사용합니다.

let user = null; // 아직 사용자가 없음

typeof null; // "object" ← 유명한 버그!

typeof null === "object"는 JavaScript 초기 구현의 버그입니다. 비트 표현에서 null의 태그가 객체와 같았던 것이 원인인데, 기존 코드 호환성 때문에 수정할 수 없습니다. null 체크는 항상 === null로 해야 합니다.

5. undefined

undefined값이 할당되지 않음을 나타내는 JavaScript가 자동으로 부여하는 값입니다.

let x;                  // undefined — 선언만, 초기화 안 됨
function fn() {}
fn();                   // undefined — 반환값 없는 함수
const obj = {};
obj.missing;            // undefined — 존재하지 않는 프로퍼티

// null vs undefined
null === undefined;     // false
null == undefined;      // true (느슨한 동등)

실용적 구분:

  • null: 개발자가 의도적으로 비움
  • undefined: JavaScript가 “아직 값 없음” 표시

6. Symbol (ES2015)

Symbol은 유일하고 변경 불가한 식별자를 만드는 데 사용합니다. 설명 인자는 디버깅용일 뿐, 유일성에 영향을 주지 않습니다.

const id1 = Symbol("id");
const id2 = Symbol("id");
id1 === id2; // false — 항상 다름!

// 객체 키로 사용 — 충돌 방지
const KEY = Symbol("secret");
const obj = {
  [KEY]: "private data",
  name: "public"
};
obj[KEY]; // "private data"
Object.keys(obj); // ["name"] — Symbol 키는 열거되지 않음

// Well-known Symbols — 언어 내장 동작 커스터마이즈
class MyCollection {
  [Symbol.iterator]() { /* ... */ }
}

7. BigInt (ES2020)

number 타입은 2^53 - 1보다 큰 정수를 정확하게 표현하지 못합니다. BigInt는 임의 크기의 정수를 처리합니다.

// number의 한계
9007199254740992 === 9007199254740993; // true! (잘못된 결과)

// BigInt는 정확하게
9007199254740992n === 9007199254740993n; // false (정확함)

const huge = 9007199254740993n;
typeof huge; // "bigint"

// 주의: number와 혼용 불가
1n + 1;   // TypeError
1n + 1n;  // 2n (OK)
Number(1n); // 1 (변환)

typeof로 원시 타입 판별

typeof 결과표

// null을 제외한 원시 타입은 typeof로 정확히 판별
typeof 42;          // "number"
typeof "hello";     // "string"
typeof true;        // "boolean"
typeof undefined;   // "undefined"
typeof Symbol();    // "symbol"
typeof 42n;         // "bigint"

// 함수는 별도
typeof function(){}; // "function"

// 객체, 배열, null은 모두 "object"
typeof {};          // "object"
typeof [];          // "object"
typeof null;        // "object" ← 버그

// null 정확한 체크
const isNull = (x) => x === null;
// 또는
const isObject = (x) => typeof x === "object" && x !== null;

원시 타입 vs 참조 타입

원시 타입은 값(value) 복사, 객체·배열 같은 참조 타입은 참조(reference) 복사입니다:

// 원시 타입 — 값 복사
let a = 42;
let b = a;
b = 100;
console.log(a); // 42 — 영향 없음

// 참조 타입 — 주소 복사
let obj1 = { x: 1 };
let obj2 = obj1;    // 같은 객체를 가리킴
obj2.x = 99;
console.log(obj1.x); // 99 — 같은 객체!

이 차이는 함수에 인자를 넘길 때도 동일하게 적용됩니다. 원시 타입은 복사본이 전달되고, 객체는 참조가 전달됩니다.


지난 글: TDZ (Temporal Dead Zone)

다음 글: number의 IEEE 754 정밀도와 함정


읽어주셔서 감사합니다. 😊