언어마다 다른 것 · 41
자바스크립트의 같음과 참·거짓
== 과 ===, 거짓 같은 값, ?? 와 ||, 실수 하나뿐인 수, undefined 와 null, 그리고 TypeScript가 막아 주는 것.
이 단원은 JavaScript · TypeScript에서 배워요.
다른 언어는 비교할 때 타입을 몰래 바꾸지 않아요.
Python "5" == 5는 그냥 False(크기 비교 "5" < 5는 TypeError), Java·C#은 컴파일 오류라 직접 변환해야 하고, 크레이콘 ==도 타입이 다르면 거짓이에요.
JavaScript는 비교하거나 참·거짓을 볼 때 타입을 몰래 바꿔요.
아래 예제는 입력으로 읽은 문자열 "5"와 "0"으로 ==와 ===, ||와 ??, 실수 계산, undefined와 null이 어떻게 다르게 나오는지 보여 줘요.
const [a, b] = require("fs").readFileSync(0, "utf8").trim().split("\n"); console.log(a == 5, a === 5, a === "5");console.log(a + 1, Number(a) + 1);console.log(0 == "", null == undefined, null === undefined); const falsy = [0, "", NaN, null, undefined, false];console.log(falsy.filter(Boolean).length, Boolean("0"), Boolean([])); const count = Number(b);console.log(count || 10, count ?? 10); console.log(0.1 + 0.2, 0.1 + 0.2 === 0.3);console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);console.log(Number.MAX_SAFE_INTEGER + 2);console.log(String(2n ** 64n)); const nan = Number("abc");console.log(nan === nan, Number.isNaN(nan)); const user = { name: "Kim" };console.log(user.age, typeof null, user.age ?? "none");import { readFileSync } from "node:fs"; const [a, b]: string[] = readFileSync(0, "utf8").trim().split("\n"); // a == 5는 컴파일 오류 TS2367(string과 number는 같을 수 없어요). any로 검사를 끄면 JS와 똑같이 돌아요.const raw: any = a;const zero: any = 0;console.log(raw == 5, raw === 5, a === "5");console.log(a + 1, Number(a) + 1);console.log(zero == "", null == undefined, null === undefined); const falsy: unknown[] = [0, "", NaN, null, undefined, false];console.log(falsy.filter(Boolean).length, Boolean("0"), Boolean([])); const count: number = Number(b);console.log(count || 10, count ?? 10); console.log(0.1 + 0.2, 0.1 + 0.2 === 0.3);console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);console.log(Number.MAX_SAFE_INTEGER + 2);console.log(String(2n ** 64n)); const nan: number = Number("abc");console.log(nan === nan, Number.isNaN(nan)); // user.age는 타입에 없으면 컴파일 오류 TS2339라서 age?: number로 적어 둬요const user: { name: string; age?: number } = { name: "Kim" };console.log(user.age, typeof null, user.age ?? "none");5 0
true false true 51 6 true true false 0 true true 10 0 0.30000000000000004 false true 9007199254740992 18446744073709551616 false true undefined object none
핵심
==는 타입이 다르면 한쪽을 바꿔서 비교해요.
그래서"5" == 5,0 == "",null == undefined가 모두true예요.===는 타입까지 같아야 해요.
바꾸는 규칙이 복잡하니 외우기보다 늘===와!==를 써요.+는 한쪽이 문자열이면 이어 붙여요."5" + 1은"51"인데"5" - 1은4예요.
입력은 늘 문자열이니 먼저Number(...)로 바꿔요.- 거짓 같은 값(falsy)은
false,0,-0,0n,"",null,undefined,NaN뿐이에요."0"과 빈 목록[]은 참이에요(Python은[]가 거짓). - '값이 없음'이 둘이에요.
undefined는 넣은 적이 없다는 뜻(없는 속성, 안 준 매개변수,return없는 함수의 값)이고,null은 일부러 넣은 "비어 있음"이에요.
둘 다 물을 때는x == null이나x ?? 기본값을 써요. NaN은 자기 자신과도 같지 않아서NaN === NaN이false예요.Number.isNaN(x)로 물어요.typeof null이"object"인 건 초기 JavaScript의 실수가 남은 거예요.
언어별로 쓰는 법
| JavaScript | 비교는 ===·!==, 기본값은 ??, 문자열은 Number(...)로 수로 바꿔요.이 함정들은 실행 중에 아무 경고 없이 지나가요 |
|---|---|
| TypeScript | 일부를 컴파일할 때 막아요: a == 5(string과 number)는 TS2367, x === NaN은 TS2845, 타입에 없는 user.age는 TS2339.strict에서는 age?: number를 쓰기 전에 undefined인지 확인하게 해요.하지만 타입은 실행 전에 지워져서 실행 중에는 그대로 JavaScript이고, any나 as를 쓰면 검사가 꺼져요(예제의 raw) |
자주 하는 실수
기본값을 ||로 줬어요
const count = 0;
console.log(count || 10, count ?? 10);→ 10 0 — ||는 왼쪽이 거짓 같으면 오른쪽을 줘서 올바른 값 0이 10으로 바뀌어요
null·undefined일 때만 오른쪽을 주는 ??를 써요.
실수를 ===로 비교했어요
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);→ 0.30000000000000004, false — 수는 모두 64비트 실수(double) 하나라서 오차가 생겨요
Math.abs(x - y) < Number.EPSILON처럼 차이로 비교해요.
아주 큰 정수를 그냥 계산했어요
console.log(Number.MAX_SAFE_INTEGER + 2);→ 9007199254740992 — 정수는 2^53 − 1(9007199254740991)까지만 정확해서 ...993이 나오지 않아요
2n 64n처럼 n을 붙인 BigInt**로 계산해요.1n + 1처럼 보통 수와 섞으면 TypeError예요.
언어마다 다른 점
비교는
비교는
===, 기본값은 ??로 쓰세요.==와 ||는 "5" == 5가 참이 되거나 0이 10으로 바뀌는 것처럼 오류 없이 다른 답을 내요.