== vs === 완전 정리 — 느슨한 동등·엄격 동등·형 변환·NaN
자바스크립트에서 값을 비교하는 == 와 === 는 한 글자 차이지만 동작이 크게 다르다. 그리고 이 차이를 모르면 "0 == '' 이 왜 true지?" 같은 당황스러운 결과를 만난다. 핵심은 하나다. == 는 비교하기 전에 타입을 맞추려고 값을 변환(형 변환)하고, === 는 변환 없이 타입과 값을 그대로 비교한다. 그래서 == 는 겉보기에 다른 값도 같다고 하는 경우가 생기고, === 는 타입까지 같아야 참이 된다. 여기에 NaN은 자기 자신과도 같지 않고, null 과 undefined 는 서로만 느슨하게 같다는 특이 규칙까지 얽히면 헷갈림이 커진다. 이 글은 == 와 === 의 근본 차이, 형 변환이 만드는 함정, 그리고 === 를 기본으로 쓰는 이유를 정리한다.

이 글의 구성
🔎 == 와 === 의 근본 차이
두 연산자의 차이는 "타입을 맞추는가"에 있다. === 는 엄격 동등(strict equality)으로, 두 값의 타입과 값이 모두 같을 때만 참이다. 타입이 다르면 값을 바꾸지 않고 바로 거짓으로 본다. 그래서 1 === "1" 은 숫자와 문자열이라 거짓이다. 반면 == 는 느슨한 동등(loose equality)으로, 타입이 다르면 값을 변환해 타입을 맞춘 뒤 비교한다(주로 숫자 쪽으로 바꾸며, 불리언이 끼면 양쪽을 단계적으로 변환한다). 1 == "1" 은 "1" 을 숫자 1로 바꿔 비교해 참이 된다.
문제는 이 형 변환 규칙이 직관과 어긋날 때가 있다는 점이다. 숫자·문자열·불리언·null·undefined가 섞이면 변환 과정이 복잡해져, 겉보기엔 전혀 다른 값이 == 로는 같다고 나온다. 0 == "" 이 참인 것이 대표적이다. 그래서 == 는 편해 보여도 예측하기 어렵고, === 는 "타입까지 같아야 한다"는 단순한 규칙이라 예측 가능하다.
핵심 — 형 변환을 하느냐 안 하느냐
=== 는 타입과 값을 그대로 비교(형 변환 없음)하고, == 는 타입을 맞추려 값을 변환한 뒤 비교한다. 그 변환 규칙이 복잡해 == 는 예상 밖 결과(0 == "" → true)를 만든다. 그래서 특별한 이유가 없으면 === 를 기본으로 쓴다.
⚖️ 헷갈리는 비교 결과 표
== 의 형 변환이 만드는 대표적인 결과를 모았다. === 와 나란히 두면 차이가 또렷하다.
| 비교 | == (느슨) | === (엄격) |
|---|---|---|
| 0, "0" | true | false |
| 0, "" | true | false |
| "", "0" | false | false |
| 0, false | true | false |
| null, undefined | true | false |
| null, 0 | false | false |
| NaN, NaN | false | false |
표에서 보듯 0 == "0", 0 == "", 0 == false 는 모두 참이다. == 가 문자열·불리언을 숫자로 바꿔 비교하기 때문이다. 반면 "" == "0" 은 둘 다 문자열이라 변환 없이 그대로 비교해 거짓이다. null == undefined 는 참이지만 null == 0 은 거짓인데, null 과 undefined 는 서로하고만 느슨하게 같고 다른 값과는 같지 않은 특별한 규칙을 따르기 때문이다. 그리고 NaN 은 == 든 === 든 자기 자신과도 같지 않다. 이 표를 외울 필요는 없다. "=== 를 쓰면 이 헷갈림이 대부분 사라진다"는 것만 기억하면 된다.
🧩 == 가 만드는 함정 4가지
함정 1 — 숫자·문자열 형 변환
0 == "0", 0 == "" 처럼 == 는 문자열을 숫자로 바꿔 비교한다. 사용자 입력값(문자열)과 숫자를 == 로 비교하면, 의도와 다르게 같다고 나올 수 있다. 이런 곳이 == 함정의 단골이다.
함정 2 — 불리언·falsy 혼동
0 == false, "" == false 가 참이라, 값의 존재 여부를 == false 로 판단하면 0이나 빈 문자열까지 걸린다. 진짜 false인지, 아니면 0·빈 문자열인지 구분하려면 === 를 쓰거나 다른 검사를 해야 한다.
함정 3 — NaN 비교
NaN 은 == 로도 === 로도 자기 자신과 같지 않다. 그래서 x === NaN 으로는 NaN 을 못 잡는다. NaN 여부는 Number.isNaN(x)이나 Object.is(x, NaN)으로 확인해야 한다.
함정 4 — null·undefined 혼동
null == undefined 는 참이지만 null === undefined 는 거짓이다. 둘을 함께 "값이 없음"으로 다루고 싶을 때 == 의 이 성질을 역이용하기도 하지만, 나머지 == 함정 때문에 조심스럽게 써야 한다.
💻 NaN·null 비교와 진단
두 가지 특수 케이스는 따로 다뤄야 한다. NaN 과 null·undefined다. 코드로 보면 명확하다.
// NaN 은 자기 자신과도 같지 않다
const x = NaN;
console.log(x === x); // false
console.log(Number.isNaN(x)); // ✓ true
// null·undefined 를 함께 잡기
const v = null;
console.log(v == null); // ✓ true (null·undefined 둘 다)
console.log(v === null); // null 만 true
NaN 검사는 반드시 Number.isNaN 을 쓴다. 비슷한 이름의 전역 isNaN 은 인자를 숫자로 변환해 검사하므로, 문자열 등에 대해 오해를 부르는 결과를 낼 수 있어 Number.isNaN 이 더 안전하다. null·undefined를 함께 다뤄야 하면 x == null 이라는 관용구가 유용하다. 이건 == 의 예외적 허용 사례로, null 과 undefined 를 한 번에 걸러 준다.
// ✓ 기본은 === 로 명확하게
if (status === "active") { ... }
if (count === 0) { ... }
// ✓ null·undefined 동시 검사만 == 허용
if (value == null) { ... } // null 또는 undefined
🛠 권장 — === 기본, 예외 처리
권장 습관은 단순하다. 기본은 === 로 비교하고, 딱 두 가지 예외만 따로 다룬다. NaN 은 Number.isNaN, null·undefined 동시 검사는 == null 이다.
동등 비교 원칙
정리하면, === 는 예측 가능한 비교의 기본값이다. 형 변환이 필요하면 자바스크립트에 맡기지 말고 Number(x)나 String(x)처럼 직접 변환한 뒤 === 로 비교하는 편이 의도가 분명하다. == 는 편해 보이지만 형 변환 규칙이 복잡해 버그의 원인이 되기 쉬우니, null 관용구 같은 특정 예외를 빼면 === 로 통일하는 게 안전하다.
💬 자주 묻는 질문 5가지
Q10 == "" 이 왜 true인가요?
== 가 비교 전에 타입을 맞추려고 빈 문자열 ""을 숫자 0으로 변환하기 때문입니다. 그러면 0과 0을 비교해 true가 되죠. === 로 하면 숫자와 문자열이라 타입이 달라 false입니다. 이런 예상 밖 결과가 == 를 피하는 이유입니다.
Q2그냥 항상 === 쓰면 되나요?
대부분 그렇습니다. === 를 기본으로 쓰면 형 변환 함정이 사라집니다. 예외는 두 가지뿐입니다. null·undefined를 함께 검사할 때의 x == null 관용구, 그리고 NaN 검사(=== 대신 Number.isNaN)입니다. 나머지는 === 로 통일하세요.
Q3NaN === NaN 이 왜 false인가요?
NaN(Not a Number)은 "특정할 수 없는 값"이라 자기 자신과도 같지 않도록 정의돼 있습니다. 그래서 === 로도 NaN을 못 잡습니다. NaN 여부는 Number.isNaN(x)로 확인하세요. 참고로 Object.is(NaN, NaN)은 true를 반환합니다.
Q4x == null 은 == 인데 써도 되나요?
이건 널리 쓰이는 예외입니다. x == null 은 x가 null이거나 undefined일 때만 true이고 0·""·false 같은 다른 falsy 값은 걸리지 않습니다. 그래서 "값이 없음(null 또는 undefined)"을 한 번에 검사할 때 안전하게 쓸 수 있습니다.
Q5isNaN 과 Number.isNaN 은 다른가요?
다릅니다. 전역 isNaN 은 인자를 먼저 숫자로 변환한 뒤 검사해서, isNaN("abc")처럼 숫자가 아닌 값에도 true를 냅니다. Number.isNaN 은 변환 없이 값이 진짜 NaN일 때만 true를 내죠. 정확한 NaN 판별에는 Number.isNaN 을 쓰는 게 안전합니다.
📌 결론
== 와 === 의 차이는 형 변환 여부다. === 는 타입과 값을 그대로 비교해 예측 가능하고, == 는 타입을 맞추려 값을 변환해 0 == "" 같은 예상 밖 결과를 만든다. 여기에 NaN 은 자기 자신과도 같지 않고, null·undefined는 서로만 느슨하게 같다는 특수 규칙이 더해진다.
실무 원칙은 다음과 같다.
🟰 기본은 === 로. 타입까지 같아야 참인 엄격 비교가 형 변환 함정을 없앤다. 비교는 === 로 통일하는 걸 기본으로 삼는다.
🔄 형 변환은 직접. 타입이 다르면 == 에 맡기지 말고 Number(x)·String(x)로 명시적으로 변환한 뒤 === 로 비교한다.
🎯 NaN·null은 따로. NaN 은 Number.isNaN 으로, null·undefined 동시 검사는 x == null 관용구로 처리한다. ESLint eqeqeq 로 == 를 자동 점검한다.
== vs === 체크리스트
본 글은 자바스크립트 동등 비교(== vs ===)와 형 변환 함정을 정리한 자료다. 코드 수정은 영향 범위를 확인한 뒤 신중히 적용한다.
#JavaScript #동등비교 #느슨한동등 #엄격동등 #형변환 #NaN #NumberisNaN #null #undefined #eqeqeq #ESLint #프론트엔드 #JS기초 #자바스크립트 #웹개발
'IT' 카테고리의 다른 글
| 파이썬 모듈 없음 오류 (ModuleNotFoundError: No module named) 진짜 원인과 해결 (0) | 2026.07.03 |
|---|---|
| JS 에러 3대장 완전 정리 — TypeError·ReferenceError·SyntaxError 한눈에 (0) | 2026.07.02 |
| let vs var 함정 완전 정리 — 스코프·호이스팅·반복문 클로저 (0) | 2026.07.02 |
| this가 undefined — 바인딩·화살표 함수 원인·해결 (0) | 2026.07.02 |
| async/await 에러 처리 완전 정리 — try-catch·allSettled·전역 처리 (0) | 2026.07.02 |
댓글