본문으로 건너뛰기
기술스택 · stack/javascript/형 변환과 비교: == 대신 ===를 쓰는 이유

JavaScript · 2장 기본

형 변환과 비교: == 대신 ===를 쓰는 이유

자바스크립트는 종류가 다른 값을 만나면 한쪽을 몰래 바꿔서 계산하거나 비교해요. 이 자동 변환이 편할 때도 있지만, 버그의 단골 원인이기도 해요. 값을 직접 바꾸는 법과 안전하게 비교하는 법을 정리했어요.

#2.5

01. 직접 바꾸기: String · Number · Boolean

값의 종류를 바꾸고 싶으면 String(), Number(), Boolean()에 넣어요. 가장 많이 쓰는 건 문자열을 숫자로 바꾸는 Number()인데, 규칙을 알아 두지 않으면 엉뚱한 결과에 놀라요.

console.log(Number('42'), Number(' 42 '), Number(''));  // 42 42 0
console.log(Number('12px'), Number('4,200'));           // NaN NaN
console.log(Number(true), Number(null), Number(undefined)); // 1 0 NaN
console.log(String(42) + '번', String(null));            // 42번 null
  • 앞뒤 공백은 무시하고, 빈 문자열은 0이 돼요. 입력 칸을 비워 둔 것을 "0을 입력함"으로 착각하기 쉬운 지점이에요.
  • 숫자로 읽을 수 없는 글자(단위 px, 천 단위 쉼표)가 섞이면 NaN이에요. '12px'에서 앞쪽 숫자만 꺼내는 parseInt는 숫자 다루기에서 다뤄요.
  • null은 0, undefined는 NaN이 돼요. 둘 다 "없음"이지만 숫자로는 다르게 바뀌어요.

웹 페이지의 입력 칸에서 읽은 값은 숫자를 쳐도 언제나 문자열이에요. 아래 칸에 10, 010, 빈칸, 10원처럼 여러 가지를 넣어 보고, 각 줄의 결과가 어떻게 바뀌는지 보세요.

02. 참 같은 값, 거짓 같은 값

if의 조건 자리에는 아무 값이나 올 수 있고, 그때 값은 불리언으로 바뀌어요. 거짓(false)이 되는 값은 딱 여덟 개예요. false, 0, -0, 0n, 빈 문자열 '', null, undefined, NaN. 나머지는 전부 참이 돼요. 문자열 '0', 공백 ' ', 빈 배열 [], 빈 객체 {}도 참이에요.

console.log(Boolean(0), Boolean(''), Boolean(null), Boolean(NaN)); // false false false false
console.log(Boolean('0'), Boolean(' '), Boolean([]), Boolean({}));  // true true true true

const stock = 0;
if (stock) {
  console.log('재고 있음');
} else {
  console.log('재고 없음 — 0은 거짓이에요');
}

위 예처럼 "값이 있는지"를 if (stock)로 확인하면 0이나 빈 문자열이 정상 값일 때 문제가 생겨요. 재고 0개, 할인율 0%, 빈 메모는 "없음"이 아니라 "0이라는 값"이니까요. 이럴 때 쓰는 ?? 연산자는 다음 글들에서 다뤄요.

03. ==와 ===

같은지 비교하는 연산자가 두 개예요. ===(엄격한 같음)는 종류까지 같아야 true예요. ==(느슨한 같음)는 종류가 다르면 한쪽을 바꾼 뒤에 비교해요. 그 바꾸는 규칙이 복잡해서 결과를 예측하기 어려워요.

①일곱 값을 서로 비교해 true인 칸을 칠해요. == 쪽은 0 · '0' · '' · false가 서로 얽혀 같다고 나오지만, === 쪽은 같은 값끼리만 같고 NaN은 자기 자신과도 같지 않아요.
console.log(0 == '');        // true
console.log('0' == false);   // true
console.log('' == '0');      // false — 앞의 둘과 이어지지 않아요
console.log(null == undefined, null == 0); // true false
console.log(NaN == NaN, NaN === NaN);      // false false

그래서 비교는 언제나 ===와 !==를 기본으로 써요. 종류가 다르면 먼저 직접 바꾼 다음 비교해요. 예외로 많이 쓰는 한 가지가 value == null이에요. ==는 null과 undefined를 서로만 같다고 보기 때문에, 이 한 줄로 "값이 없음"을 둘 다 잡아낼 수 있어요.

NaN은 어떤 값과도, 심지어 자기 자신과도 같지 않아요. 계산 결과가 NaN인지 확인할 때는 Number.isNaN(value)를 써요.

04. 문자열끼리 크기를 비교하면

< >로 문자열 두 개를 비교하면 숫자 크기가 아니라 사전 순서로 비교해요. 첫 글자부터 하나씩 비교하다가 처음 다른 글자에서 결정해요. 그래서 '10'이 '9'보다 작다고 나와요.

console.log('10' < '9');                  // true — '1'이 '9'보다 앞이에요
console.log(Number('10') < Number('9'));  // false
console.log('apple' < 'banana', 'Zoo' < 'apple'); // true true — 대문자가 소문자보다 앞
console.log('10' < 9);                    // false — 한쪽이 숫자면 숫자로 비교해요

입력 칸 두 개의 값을 비교하거나, 문자열로 저장된 가격을 비교할 때 이 버그가 자주 생겨요. 이것도 비교 전에 숫자로 바꾸면 사라져요.

아래 여섯 줄의 결과를 먼저 예상해 보고 실행해 보세요. 그다음 ==를 모두 ===로 바꿨을 때 결과가 바뀌는 줄을 찾아보세요.

console.log(1 == '1');
console.log(false == 0);
console.log(null == false);
console.log(undefined == null);
console.log('5' > '40');
console.log(Boolean('false'));
해답 보기

차례로 true, true, false, true, true, true예요.

  • null == false가 false인 건, ==가 null을 undefined 말고는 무엇과도 같다고 보지 않기 때문이에요.
  • '5' > '40'은 사전 순서 비교라서 '5'가 '4'보다 뒤예요.
  • 문자열 'false'는 빈 문자열이 아니라서 참이에요.
  • ===로 바꾸면 첫째 · 둘째 · 넷째 줄이 false로 바뀌어요.

05. 실전 포인트

  • 언제 쓰나요? 밖에서 들어온 값(입력 칸 · 주소 · 서버 응답)은 들어오는 자리에서 한 번 원하는 종류로 바꿔 두고, 그 뒤로는 바뀐 값만 써요. 비교는 === · !==로 해요.
  • 대신 쓰는 것: ==는 value == null 한 가지 용도로만 써요. ESLint의 eqeqeq 규칙(3장)을 켜면 나머지 ==를 찾아 줘요. NaN 확인은 Number.isNaN이에요.
  • 흔한 실수: 빈 입력이 Number('')로 0이 되어 "0을 입력함"으로 처리되는 것, if (count)가 0을 "없음"으로 취급하는 것, 문자열 숫자를 <로 비교하는 것이에요.

정리

  • Number()는 공백을 무시하고, 빈 문자열을 0으로, 읽을 수 없는 글자를 NaN으로 바꿔요.
  • 거짓이 되는 값은 false · 0 · -0 · 0n · '' · null · undefined · NaN 여덟 개뿐이에요.
  • 비교는 ===가 기본이에요. ==는 value == null에만 써요.
  • 문자열끼리의 < · >는 사전 순서예요. 숫자로 바꾼 뒤 비교해요.
SIMPLE · 기술스택 / JavaScript — 2장 기본