프론트엔드/JavaScript

(JavaScript) == vs === 차이와 타입 변환(Type Coercion)

그린티_ 2026. 2. 11. 12:18
반응형

서론

JavaScript로 개발하다 보면 조건문에서 =====를 뭘 쓸지 고민하게 됨
처음엔 "둘 다 같은 거 비교하는 거 아닌가?" 싶었는데, 실제로 써보니 ==가 예상과 다르게 동작하는 경우가 꽤 있었음

예를 들어 API에서 받은 데이터가 문자열 "1"인데 숫자 1과 비교할 때, ==로 비교하면 true가 나오길래 편하다고 생각했음
근데 나중에 null == undefinedtrue라든가, "" == 0true라는 걸 보고 "이건 좀 위험하다" 싶었음

면접에서도 =====의 차이는 거의 무조건 나오는 질문이고, 타입 변환(Type Coercion)까지 설명할 수 있어야 제대로 된 답변이 되겠다 싶어서 정리해봄


본론

1. == (동등 연산자, Loose Equality)

==는 비교할 때 타입이 다르면 타입을 변환한 후 비교함

console.log(1 == '1');     // true — 문자열 '1'을 숫자 1로 변환 후 비교
console.log(true == 1);    // true — true를 숫자 1로 변환 후 비교
console.log(null == undefined); // true — 특별 규칙
console.log('' == 0);      // true — 빈 문자열을 숫자 0으로 변환 후 비교

이렇게 자동으로 타입을 맞춰주는 걸 타입 변환(Type Coercion)이라고 함
편해 보이지만, 예상치 못한 true가 나오는 경우가 많아서 버그의 원인이 됨


2. === (일치 연산자, Strict Equality)

===타입 변환 없이 타입과 값 모두 같아야 true를 반환함

console.log(1 === '1');     // false — 숫자 vs 문자열, 타입이 다름
console.log(true === 1);    // false — 불리언 vs 숫자, 타입이 다름
console.log(null === undefined); // false — null vs undefined, 타입이 다름
console.log('' === 0);      // false — 문자열 vs 숫자, 타입이 다름

타입까지 체크하니까 의도하지 않은 비교를 방지할 수 있음
그래서 실무에서는 거의 항상 ===를 사용함


3. 타입 변환(Type Coercion) 규칙 정리

==가 내부적으로 어떻게 타입을 변환하는지 알아야 면접에서 제대로 설명할 수 있음

3-1. 숫자와 문자열 비교 → 문자열을 숫자로 변환

console.log(1 == '1');   // true — Number('1') → 1
console.log(0 == '');    // true — Number('') → 0
console.log(0 == '0');   // true — Number('0') → 0
console.log('' == '0');  // false — 둘 다 문자열이라 변환 없이 비교

3-2. 불리언이 포함된 비교 → 불리언을 숫자로 변환

console.log(true == 1);    // true — Number(true) → 1
console.log(false == 0);   // true — Number(false) → 0
console.log(true == '1');  // true — true → 1, '1' → 1
console.log(false == '');  // true — false → 0, '' → 0

3-3. null과 undefined

console.log(null == undefined);  // true — 특별 규칙 (서로만 같음)
console.log(null == 0);          // false — null은 0으로 변환 안 됨
console.log(null == '');         // false
console.log(null == false);      // false
console.log(undefined == 0);     // false
console.log(undefined == '');    // false
console.log(undefined == false); // false

nullundefined==로 비교하면 서로에게만 true이고, 나머지는 전부 false
이건 외워야 함

3-4. 객체와 원시 타입 비교 → 객체를 원시 타입으로 변환

console.log([1] == 1);     // true — [1].valueOf() → [1], [1].toString() → '1' → 1
console.log([''] == '');   // true — [''].toString() → ''
console.log([null] == ''); // true — [null].toString() → ''

객체는 valueOf()toString() 순서로 원시 값으로 변환됨


4. 타입 변환의 종류

JavaScript에서 타입 변환은 두 가지로 나뉨

4-1. 암묵적 타입 변환 (Implicit Coercion)

자바스크립트 엔진이 자동으로 타입을 변환하는 것

// 문자열 변환
console.log(1 + '2');       // '12' — 숫자가 문자열로 변환
console.log('5' - 1);       // 4 — 문자열이 숫자로 변환 (- 연산자는 숫자만 가능)

// 불리언 변환
if ('hello') {
  console.log('truthy!');   // 출력됨 — 비어있지 않은 문자열은 truthy
}

if (0) {
  console.log('출력 안 됨'); // 0은 falsy
}

+ 연산자는 문자열이 하나라도 있으면 문자열 결합으로 동작함
-, *, / 연산자는 숫자로 변환을 시도함
이 차이 때문에 실수가 생기기 쉬움

4-2. 명시적 타입 변환 (Explicit Coercion)

개발자가 직접 타입을 변환하는 것

// 문자열로 변환
String(123);        // '123'
(123).toString();   // '123'

// 숫자로 변환
Number('123');      // 123
parseInt('123px');  // 123 — 숫자 부분만 파싱
parseFloat('3.14'); // 3.14
+'123';             // 123 — 단항 + 연산자

// 불리언으로 변환
Boolean(1);         // true
Boolean('');        // false
!!0;                // false — !! 패턴 (실무에서 자주 씀)
!!'hello';          // true

실무에서는 암묵적 변환에 의존하지 않고 명시적으로 변환하는 게 안전함


5. Falsy와 Truthy 값 정리

타입 변환을 이해하려면 falsy/truthy를 알아야 함

Falsy 값 (false로 평가되는 값, 외울 것!)

Boolean(false);     // false
Boolean(0);         // false
Boolean(-0);        // false
Boolean(0n);        // false (BigInt)
Boolean('');        // false
Boolean(null);      // false
Boolean(undefined); // false
Boolean(NaN);       // false

이 8가지만 falsy이고, 나머지는 전부 truthy

주의: 헷갈리는 truthy 값들

Boolean([]);        // true — 빈 배열도 truthy!
Boolean({});        // true — 빈 객체도 truthy!
Boolean('0');       // true — 문자열 '0'도 truthy!
Boolean('false');   // true — 문자열 'false'도 truthy!

빈 배열 []과 빈 객체 {}가 truthy라는 건 자주 실수하는 부분임


6. 실무에서 겪을 수 있는 문제

Before: == 때문에 생기는 버그

// API에서 받은 응답값 체크
const response = { status: 0 };

// ❌ == 사용 시
if (response.status == false) {
  console.log('실패!'); // 출력됨 — 0 == false → true
}
// 의도: status가 false인지 확인
// 실제: status가 0인데 false로 판단해버림

// ❌ 또 다른 케이스
const input = '';

if (input == false) {
  console.log('입력값 없음'); // 출력됨 — '' == false → true
}
// 빈 문자열과 false를 같다고 판단

After: === 사용으로 명확한 비교

// ✅ === 사용
const response = { status: 0 };

if (response.status === false) {
  console.log('실패!'); // 출력 안 됨 — 0 !== false (타입이 다름)
}

if (response.status === 0) {
  console.log('status가 0임'); // 이렇게 명확하게 비교해야 함
}

// ✅ 입력값 체크도 명확하게
const input = '';

if (input === '' || input === null || input === undefined) {
  console.log('입력값 없음');
}

// 또는 더 간결하게
if (!input) {
  console.log('입력값 없음'); // falsy 체크
}

7. == 를 써도 괜찮은 경우

===를 기본으로 쓰되, ==가 유용한 케이스가 딱 하나 있음

// null 또는 undefined인지 한 번에 체크할 때
if (value == null) {
  // value가 null이거나 undefined일 때만 여기 들어옴
  // 0, '', false는 여기 안 들어옴
}

// === 로 하면 두 번 써야 함
if (value === null || value === undefined) {
  // 같은 동작이지만 더 길음
}

value == nullnullundefinedtrue로 판단하기 때문에, 이 패턴은 실무에서도 종종 사용됨
다만 ESLint 규칙에 따라 팀마다 허용 여부가 다를 수 있음


8. 면접 예상 질문 & 답변

Q1. == 와 === 의 차이는 무엇인가요?

==(동등 연산자)는 비교 시 타입이 다르면 타입 변환을 수행한 후 비교합니다. ===(일치 연산자)는 타입 변환 없이 타입과 값 모두 동일해야 true를 반환합니다. 예를 들어 1 == '1'true이지만, 1 === '1'false입니다.

Q2. 타입 변환(Type Coercion)이란 무엇인가요?

타입 변환은 JavaScript 엔진이 연산 시 피연산자의 타입을 자동으로 변환하는 것을 말합니다. 암묵적 변환(Implicit)은 엔진이 자동으로 수행하고, 명시적 변환(Explicit)은 Number(), String(), Boolean() 등을 사용해 개발자가 직접 수행합니다.

Q3. falsy 값을 모두 말해보세요.

false, 0, -0, 0n(BigInt), ''(빈 문자열), null, undefined, NaN 총 8가지입니다. 이 외의 값은 모두 truthy이며, 빈 배열 []과 빈 객체 {}도 truthy입니다.

Q4. null == undefined가 true인 이유는?

ECMAScript 명세에서 == 연산 시 nullundefined는 서로에게만 동등하다고 정의되어 있습니다. 이 둘은 "값이 없음"을 나타내는 공통점이 있어서 동등 연산에서 같다고 처리됩니다. 다만 ===로 비교하면 타입이 다르므로(null은 object, undefined는 undefined) false가 됩니다.

Q5. 실무에서 ==와 ===중 어떤 걸 사용해야 하나요?

기본적으로 항상 ===를 사용하는 것이 좋습니다. 타입 변환으로 인한 예상치 못한 버그를 방지할 수 있기 때문입니다. 유일하게 == null 패턴은 nullundefined를 한 번에 체크할 수 있어서 실무에서 허용되는 경우가 있습니다.


결론

=====는 단순해 보이지만, 타입 변환까지 이해해야 제대로 쓸 수 있음

  • ==: 타입이 다르면 변환 후 비교 (느슨한 비교)
  • ===: 타입 변환 없이 타입 + 값 모두 비교 (엄격한 비교)
  • 타입 변환: 숫자 ↔ 문자열, 불리언 → 숫자, 객체 → 원시 타입 순서로 변환됨
  • falsy 값: false, 0, -0, 0n, '', null, undefined, NaN
  • 실무 원칙: 항상 === 사용, == null 패턴만 예외적으로 허용
구분 == (동등) === (일치)
타입 변환 수행함 수행 안 함
1 == '1' / 1 === '1' true false
null == undefined / null === undefined true false
'' == false / '' === false true false
사용 권장 == null 패턴만 기본으로 사용

프로젝트에서 ESLint의 eqeqeq 규칙을 켜두면 ==를 쓸 때 경고가 나와서 실수를 방지할 수 있음
앞으로도 ===를 기본으로 쓰고, 타입이 애매할 땐 명시적으로 변환해서 비교하는 습관을 들여야겠음!

반응형