== vs ===, 그리고 NaN: 자바스크립트 동등 비교의 함정
자바스크립트에서 ==와 ===는 한 글자 차이지만 결과는 완전히 다를 수 있습니다. 이 차이가 디버깅에 몇 시간을 날리는 원인이 됩니다.
== 는 형을 맞춘 뒤 비교한다
느슨한 비교(==)는 양쪽 타입이 다르면 암묵적으로 형변환한 뒤 비교합니다.
0 == "0"; // true (문자열을 숫자로)
0 == ""; // true (빈 문자열 → 0)
0 == false; // true (false → 0)
null == undefined; // true
1 == "1px"; // false ("1px"는 숫자로 NaN)
규칙이 직관적이지 않아서, 의도하지 않은 true가 튀어나옵니다.
=== 는 타입까지 본다
엄격한 비교(===)는 타입이 다르면 무조건 false입니다. 형변환이 없으니 예측 가능합니다.
0 === "0"; // false
0 === false; // false
1 === 1; // true
기본은 ===를 쓰세요. 형변환이 정말 필요하면 명시적으로 Number(x), String(x)로 변환한 뒤 비교하는 편이 안전합니다.
NaN: 자기 자신과도 다르다
NaN(Not a Number)은 어떤 값과도, 심지어 자기 자신과도 같지 않습니다.
NaN === NaN; // false (!)
그래서 "이 값이 NaN인가?"는 ===로 못 잡습니다. 대신:
Number.isNaN(value); // 권장: 진짜 NaN만 true
// 주의: 전역 isNaN()은 형변환을 해서 isNaN("a")도 true가 됨
null 과 undefined 구분
null == undefined; // true (느슨하게는 같음)
null === undefined; // false (엄격하게는 다름)
let x; // undefined
const y = null; // 의도적 "값 없음"
"값을 받아본 적 없음"은 undefined, "의도적으로 비워둠"은 null로 구분하는 관례를 따르면 코드 의도가 분명해집니다.
빈 값 안전하게 확인하기
null/undefined만 걸러내고 0이나 ""는 통과시키고 싶을 때, 널 병합 연산자가 깔끔합니다.
const port = config.port ?? 3000; // null/undefined일 때만 3000
// config.port || 3000 은 0도 3000으로 바꿔버림 (버그 위험)
마무리 체크리스트
- 동등 비교는 항상
===를 기본으로 - 형변환이 필요하면 명시적으로 변환
- NaN 검사는
Number.isNaN() - "없음" 처리는
||대신??로0·""오작동 방지
==의 형변환 표를 외우는 것보다, ===를 습관화하는 편이 훨씬 빠르고 안전합니다.
함께 보면 좋은 글
자바스크립트 비동기 완벽 가이드: Promise와 async/await 제대로 쓰기
콜백 지옥부터 async/await까지 자바스크립트 비동기 처리의 핵심을 정리합니다. Promise 체이닝, 에러 처리, 병렬 실행(Promise.all)까지 실무 예제로 익혀보세요.
React key는 왜 index를 쓰면 안 될까: 리스트 렌더링의 함정
key의 역할(재조정), index를 key로 쓸 때 생기는 상태 꼬임·성능 저하, 안정적인 고유 id를 써야 하는 이유를 예제로 설명합니다.
CSS Flexbox vs Grid 차이와 선택 기준: 1차원 vs 2차원 레이아웃
Flexbox와 Grid는 언제 무엇을 써야 할까요? 1차원과 2차원이라는 핵심 차이부터 실전 코드, 선택 기준까지 한 번에 정리합니다. 더 이상 헷갈리지 마세요.