FEInterview Prep

Github Pages

자바스크립트에서 `NaN !== NaN`인 이유 (그리고 그 뒤에 숨은 IEEE 754 이야기)

NaN !== NaN 은 자바스크립트의 변덕이 아니다. 1985년 IEEE 754 가 *프로그램이 죽지 않고 계산을 이어가도록* 채택한 의도된 설계로, 하드웨어의 ucomisd 명령어까지 거슬러 올라간다.

2025-11-18·6분 읽기
JavaScript
원문 보기 ↗

핵심 요약

(1) NaN !== NaN 은 의도된 설계isnan() API 가 없던 시절 x != x 트릭으로 감지하라고. (2) 하드웨어 수준 — x86 의 ucomisd 명령어가 비교 시 PF(Parity Flag) 를 세팅해 NaN 이면 jnp 가 점프하지 않는다. CPU 가 직접 처리하는 만큼 빠르고, 모든 언어가 동일하게 동작. (3) NaN 의 비트 패턴 — IEEE 754 double 의 지수가 0x7FF 이고 가수가 0 이 아닌 모든 값. quiet NaN 과 signaling NaN 두 종. (4) 자바스크립트의 가드 선택:

  • value !== value — 빠른 트릭, 가독성 떨어짐
  • isNaN(value)문자열도 변환 후 검사 → 위험
  • Number.isNaN(value)진짜 NaN 만권장
  • Object.is(value, NaN) — 동작은 같으나 의도 명확. (5) 왜 NaN 이 필요한가 — 0/0 같은 정의되지 않은 연산에서 프로그램이 죽지 않고 계산을 이어가도록 한 결정. NaN 은 산술 연산을 통해 전파되므로 마지막에 한 번만 검증 해도 안전.

NaN'자바스크립트의 이상한 값' 이 아니라 'IEEE 754 부동소수점 표준이 정의한 — 하드웨어 단계에서 처리되는 — 오류 표현 값' 으로 본다. NaN !== NaNisnan() 함수가 없던 시절 x != x 로 NaN 을 감지하기 위한 의도된 설계이며, typeof NaN === 'number' 인 이유는 NaN 이 별도 타입 이 아니라 숫자 시스템의 일부 이기 때문이다.

이 이해가 없으면 NaN 가드 를 잘못 짜고, 폼 검증/계산 로직에서 조용히 깨지는 코드를 만든다.

  • value === NaN항상 false — 평범한 비교 연산자로는 NaN 을 절대 잡을 수 없다
  • isNaN()문자열도 강제 변환 후 검사라 isNaN('foo') 가 true → 실수의 원인
  • Number.isNaN()순수하게 NaN 만 — 안전한 가드의 디폴트
  • parseInt('abc'), 0/0, Math.sqrt(-1), ∞ - ∞ 가 모두 NaN 을 만들 수 있고, 그 NaN 은 모든 산술 연산을 통해 전파 된다
  • 전파성 덕분에 한 번 NaN 이 끼면 계산 끝까지 살아남으므로 배치 결과만 마지막에 검증 해도 안전

면접에서 왜 NaN 이 number 인가 는 표면 질문이고, NaN 가드의 안전한 방법 까지 답할 수 있어야 한다.

학습 포인트

면접 답변으로 연결할 학습 포인트입니다.

안전한 NaN 가드는 `Number.isNaN`

전역 isNaN() 은 인자를 Number 로 강제 변환 한 뒤 검사하기 때문에 문자열도 NaN 으로 판정한다.

isNaN('foo');        // true  — 'foo' → NaN 으로 변환
isNaN(undefined);    // true  — undefined → NaN
isNaN({});           // true  — {} → NaN

Number.isNaN('foo'); // false — 진짜 NaN 만
Number.isNaN(NaN);   // true
Object.is(NaN, NaN); // true

// 트릭 (가독성 ↓)
const v = 0/0;
v !== v;             // true

폼 입력 검증·외부 데이터 파싱에서 isNaN() 을 쓰면 문자열 입력을 모두 NaN 으로 분류 하는 버그가 생긴다.

Number.isNaNisNaNObject.is강제 변환
자주 하는 오해

'isNaN 이 짧으니 그게 표준' 이라고 생각하는 것. ES2015 부터 Number.isNaN 이 표준 가드다.

NaN 은 *전파* 된다 — 마지막에 한 번만 검증

산술 연산에 NaN 이 들어오면 결과는 무조건 NaN. 즉 중간 단계마다 가드 할 필요 없이 마지막에 한 번만 검증해도 모든 오류 경로가 잡힌다.

const total = parseFloat(input1) + parseFloat(input2) * tax;
if (Number.isNaN(total)) {
  return showError('숫자만 입력하세요');
}

각 단계마다 if-NaN 을 박는 것보다 단순하다. 단, Math.max([]), Math.min([]) 처럼 NaN 이 아닌 다른 값 을 반환하는 케이스는 별도 가드 필요.

NaN 전파방어적 프로그래밍조기 반환
자주 하는 오해

각 산술 단계마다 Number.isNaN 을 박는 것. 코드는 길어지고 성능은 차이 없는데 안전성은 동일하다.

`typeof NaN === 'number'` 의 의미

NaN 은 Number 타입 의 한 값이다. JS 의 number 는 IEEE 754 double 이고, 그 표준이 NaN 을 number 의 한 패턴 으로 정의했기 때문.

IEEE 754 double (64-bit):
  부호(1) | 지수(11) | 가수(52)

  지수가 0x7FF + 가수가 0 → ±Infinity
  지수가 0x7FF + 가수 ≠ 0 → NaN (양/음, quiet/signaling 구분)

그래서 NaN, Infinity, -Infinity 는 모두 typeof === 'number' 이고 Number.isFinite 로만 진짜 유한 한 값을 가려낼 수 있다.

IEEE 754Number.isFiniteInfinitydouble precision
자주 하는 오해

typeof x === 'number' 만으로 유효한 숫자 라고 판단하는 것. NaN/Infinity 가 통과한다 — Number.isFinite 가 더 안전한 가드.

읽는 순서

  1. 1이론

    MDN 의 Number.isNaN/Number.isFinite/Object.is 페이지를 비교하고 언제 어느 것을 쓰는지 표로 정리.

  2. 2구현

    ESLint no-restricted-globals 로 전역 isNaN/isFinite 사용을 금지해본다. 기존 위반을 모두 Number.* 로 교체.

  3. 3실무

    폼 입력 컴포넌트의 검증 로직을 Number.isFinite 기반으로 통일하고, 단위 테스트로 비숫자 문자열 / Infinity / NaN 케이스를 모두 추가.

  4. 4설명

    팀에 'NaN 가드의 4가지 방법과 디폴트' 5분 발표. ===/isNaN/Number.isNaN/Object.is 비교.

면접 연결 질문

medium`isNaN('foo')` 와 `Number.isNaN('foo')` 의 결과가 다른 이유와, 어느 것을 *디폴트로* 써야 하는지 설명해보세요.
힌트

[감점 답변] '전자가 더 관대하다'. [좋은 답변] 전자는 인자를 Number 로 강제 변환 후 검사 → 'foo'NaN 이라 true. 후자는 진짜 NaN 일 때만 true. 폼/외부 데이터 검증에서는 Number.isNaN (또는 Object.is(x, NaN)) 이 안전한 디폴트.

medium사용자 입력 `'12px'` 를 받아 *숫자로 사용 가능한지* 검증하는 함수를 작성해보세요.
힌트

[감점 답변] Number(input)isNaN. [좋은 답변]

function parseNumeric(input) {
  const n = Number(input);
  if (!Number.isFinite(n)) return null; // NaN 도 Infinity 도 거름
  return n;
}

isNaNInfinity 를 통과시키고, Number.isNaN'12px'NaN 을 못 잡는다 (Number 변환 후 NaN 이긴 하지만, 함수 사용자 입장에선 유한 숫자 만 원한다).

자기 점검

본인 코드의 `isNaN(...)` 호출을 모두 찾아 *문자열 입력에서 의도와 어긋나지 않는지* 검토해보세요.
Number.isNaNNumber.isFinite강제 변환
자주 하는 오해

'전역 isNaN 이 표준이다'. 사실 Number.isNaN 이 ES2015 부터의 안전 가드다.