티스토리 뷰

JavaScript를 개발하거나 디버깅할 때 가장 빈번하게 접하는 이상 현상 중 하나가 NaN 오류임. JavaScript에서 NaN(Not‑a‑Number)은 “숫자가 아님”을 의미하지만, 기술적으로는 typeof NaN === "number"로 평가되는 특수한 숫자 값이다. 즉, NaN은 숫자 타입이면서도 유효한 수치가 아닌 결과를 나타낸다. 이는 개발자가 산술 연산을 기대했지만 입력값이나 계산 과정에서 유효하지 않은 값이 포함될 때 나타난다. 예를 들어 문자열을 숫자로 연산하거나 선언만 한 변수를 연산에 넣으면 NaN이 반환되며, 이후 계산 전체가 NaN으로 전파된다. 또한 NaN은 비교 연산(==, ===)으로도 판별할 수 없고, NaN === NaN은 항상 false를 반환한다는 점에서 혼란을 가중시킨다. 이런 특성 때문에 단순 기능 오류처럼 보이지만 실제로는 입력값/자료의 유효성 검증 누락이 원인인 경우가 대부분이다.

 

 

NaN이 발생하는 근본적 메커니즘

JavaScript는 산술 연산 중 비정상적이거나 정의되지 않은 결과를 반환할 때 IEEE 754 부동소수점 연산 표준을 따른다. 이 표준은 잘못된 산술 결과를 예외로 던지지 않고 NaN이라는 특수값으로 나타낸다. 예컨대 0/0 또는 문자열이 포함된 연산결과는 유효한 수로 해석될 수 없으므로 NaN을 발생시킨다.

 

구체적인 발생 시나리오는 다음과 같다:

 

  • 숫자로 변환할 수 없는 문자열 입력 → Number("abc")는 NaN 반환
  • undefined 또는 값이 할당되지 않은 변수와의 연산 → NaN
  • 잘못된 타입 강제 변환 → "20px" - 5 → NaN
  • 체인형 연산에서 NaN 전파 → 앞 단계 NaN이면 이후 결과 모두 NaN

이러한 NaN은 비교 연산자(===, !==)로는 판별할 수 없어, 전통적인 “값 비교” 방식이 아니라 내장 함수 또는 특수 비교가 필요하다.

 

 

NaN 판별 및 예방 전략

NaN을 정확히 식별하고 안정적으로 처리하는 것은 대규모 애플리케이션의 신뢰성을 결정짓는 핵심 요소임. 다음 는 일반적인 NaN 검출 및 대체 처리 방법을 비교한 것이다.

검출/처리 방식 NaN 검출 정확도 Type Coercion 영향 설명
Number.isNaN(x) 높음(정확) 없음 값이 실제 NaN일 때만 true 반환
isNaN(x) 중간 있음 숫자로 강제 변환 후 NaN인지 판별
x !== x 높음(기준적) 없음 NaN의 유일한 성질을 활용한 판별
Object.is(x, NaN) 높음 없음 ES6+ 환경에서 NaN 비교용으로 안정적임
  1. 입력을 산술 연산 전에 Number.isNaN()으로 선검증한다. 예: let v = Number(input); if (Number.isNaN(v)) handleError();
  2. 값 변환 시 || 0 또는 ?? 0 같은 안전한 기본값을 적용한다. 예: let count = Number(data.count) ?? 0;
  3. undefined/null은 연산 전에 처리한다. 예: value = value ?? 0;
  4. 문자열 파싱은 parseIntparseFloat을 잘라내거나, 정규식으로 숫자 부분만 처리한다.

 

전문가 조언 & 팩트체크

  • isNaN vs Number.isNaN: 전역 isNaN()는 타입 강제 변환이 있어 "hello" 같은 비숫자 문자열도 true로 판단한다. 반면 Number.isNaN()는 값이 진짜 NaN인 경우만 true를 반환한다.
  • NaN은 자기 자신과 같지 않음: NaN === NaN은 false를 반환하므로 절대 직접 비교를 사용하지 말아야 한다.
  • Object.is()는 NaN을 정확히 비교할 수 있는 ES6+ 기능이며, 많은 최신 코드베이스에서 채택되고 있다.
  • 유한성 검증: isFinite()를 통해 NaN, Infinity 또는 -Infinity 여부를 검증해 추가적인 논리 오류를 방지할 수 있다.

여기까지 읽어주셔서 감사합니다. 다음에는 본 내용을 응용한 심화 사례를 준비해 보도록 하겠습니다.