2.3 타입 변환 (Type Coercion)
타입 변환이란?
JavaScript에서 타입 변환은 두 가지 방식으로 발생합니다.
- 명시적 변환(Explicit Conversion): 개발자가 의도적으로 타입을 변환
- 암시적 변환(Implicit Coercion): JavaScript 엔진이 자동으로 타입을 변환
명시적 타입 변환
숫자로 변환
// Number() 함수
console.log(Number("42")); // 42
console.log(Number("3.14")); // 3.14
console.log(Number("")); // 0
console.log(Number(" 42 ")); // 42 (공백 제거 후 변환)
console.log(Number("42abc")); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number([])); // 0
console.log(Number([1])); // 1
console.log(Number([1, 2])); // NaN
// parseInt() / parseFloat() - 문자열을 숫자로
console.log(parseInt("42px")); // 42 (숫자 부분만 추출)
console.log(parseInt("3.14")); // 3 (정수만)
console.log(parseFloat("3.14px")); // 3.14
console.log(parseInt("0xFF", 16)); // 255 (16진수 파싱)
console.log(parseInt("1010", 2)); // 10 (2진수 파싱)
// 단항 + 연산자 (빠른 변환)
console.log(+"42"); // 42
console.log(+"3.14"); // 3.14
console.log(+""); // 0
console.log(+"abc"); // NaN
문자열로 변환
// String() 함수
console.log(String(42)); // "42"
console.log(String(3.14)); // "3.14"
console.log(String(true)); // "true"
console.log(String(false)); // "false"
console.log(String(null)); // "null"
console.log(String(undefined)); // "undefined"
console.log(String([])); // ""
console.log(String([1, 2, 3])); // "1,2,3"
// toString() 메서드
console.log((42).toString()); // "42"
console.log((255).toString(16)); // "ff" (16진수 문자열)
console.log((10).toString(2)); // "1010" (2진수 문자열)
// 템플릿 리터럴 (가장 가독성 좋음)
const num = 42;
const str = `${num}`; // "42"
불리언으로 변환
// Boolean() 함수
// Falsy 값들:
console.log(Boolean(false)); // false
console.log(Boolean(0)); // false
console.log(Boolean(-0)); // false
console.log(Boolean(0n)); // false
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
// 나머지는 모두 Truthy:
console.log(Boolean(1)); // true
console.log(Boolean("0")); // true (!)
console.log(Boolean("false")); // true (!)
console.log(Boolean([])); // true (!)
console.log(Boolean({})); // true (!)
// !! 이중 부정으로 불리언 변환
console.log(!!0); // false
console.log(!!1); // true
console.log(!!""); // false
console.log(!!"hello"); // true
암시적 타입 변환 (형변환 함정)
JavaScript가 자동으로 타입을 변환하는 규칙을 이해하면 예상치 못한 버그를 방지할 수 있습니다.
+ 연산자: 덧셈 vs 문자열 연결
// 숫자 + 숫자 = 숫자
console.log(1 + 2); // 3
// 숫자 + 문자열 = 문자열 (문자열 연결)
console.log(1 + "2"); // "12"
console.log("1" + 2); // "12"
// 문자열 + 불리언 = 문자열
console.log("true: " + true); // "true: true"
console.log("" + null); // "null"
console.log("" + undefined); // "undefined"
// 유명한 함정들
console.log([] + []); // "" (빈 문자열)
console.log([] + {}); // "[object Object]"
console.log({} + []); // "[object Object]" 또는 0 (컨텍스트에 따라)
console.log("5" + 3); // "53" (!)
console.log("5" - 3); // 2 (산술 연산에서는 숫자로 변환)
console.log("5" * "3"); // 15
console.log(true + true); // 2 (1 + 1)
console.log(true + false); // 1
console.log(false + false); // 0
- * / 연산자: 항상 숫자 변환
console.log("10" - 5); // 5 (문자열 "10"이 숫자로 변환)
console.log("10" * 2); // 20
console.log("10" / 2); // 5
console.log("10" % 3); // 1
console.log(true - 1); // 0 (true → 1)
console.log(null - 1); // -1 (null → 0)
console.log(undefined - 1); // NaN (undefined → NaN)
== vs === (느슨한 비교 vs 엄격한 비교)
엄격한 비교 ===
타입과 값이 모두 동일해야 true
console.log(1 === 1); // true
console.log(1 === "1"); // false (타입 다름)
console.log(true === 1); // false
console.log(null === null); // true
console.log(null === undefined); // false
console.log(NaN === NaN); // false (!)
느슨한 비교 ==
타입 강제 변환 후 비교 (Abstract Equality Comparison)
// 숫자와 문자열: 문자열을 숫자로 변환
console.log(1 == "1"); // true ("1" → 1)
console.log(0 == ""); // true ("" → 0)
console.log(0 == "0"); // true
// null과 undefined: 서로만 같음
console.log(null == undefined); // true
console.log(null == false); // false (!)
console.log(null == 0); // false (!)
// 불리언: 불리언을 숫자로 변환
console.log(true == 1); // true (true → 1)
console.log(false == 0); // true (false → 0)
console.log(true == "1"); // true
// 객체와 원시값: valueOf/toString 호출
console.log([] == false); // true ([] → "" → 0, false → 0)
console.log([] == ""); // true
console.log([1] == 1); // true
// 헷갈리는 예제들
console.log("" == false); // true
console.log(" " == false); // false (공백은 0이 아님!)
console.log(0 == false); // true
console.log("0" == false); // true
== 비교 원칙 (기억하기)
규칙 순서:
1. 타입 같음 → 값만 비교
2. null == undefined → true
3. 숫자 vs 문자열 → 문자열을 숫자로
4. 불리언 포함 → 불리언을 숫자로
5. 객체 vs 원시 → 객체를 원시값으로 변환
권장: 항상 === 사용하고 ==는 피하세요.
안전한 타입 변환 패턴
// 안전한 숫자 변환 패턴
function toNumber(value) {
const num = Number(value);
return Number.isNaN(num) ? 0 : num; // NaN이면 기본값 0
}
console.log(toNumber("42")); // 42
console.log(toNumber("abc")); // 0 (NaN 대신 기본값)
console.log(toNumber("")); // 0
// 정수 변환 (소수점 버림)
const toInt = (v) => Math.trunc(Number(v)) || 0;
console.log(toInt("3.7")); // 3
console.log(toInt("abc")); // 0
// 안전한 문자열 변환
function toString(value) {
if (value === null || value === undefined) return '';
return String(value);
}
// 불리언 변환: 명확한 값만 true 처리
function toBoolean(value) {
if (typeof value === 'string') {
return !['false', '0', 'no', ''].includes(value.toLowerCase());
}
return Boolean(value);
}
console.log(toBoolean("false")); // false (일반 Boolean은 true)
console.log(toBoolean("true")); // true
console.log(toBoolean("0")); // false (일반 Boolean은 true)
고수 팁
타입 변환을 명확하게 표현하기
// 나쁜 예: 암시적 변환에 의존
const count = "5" - 0; // 5 (의도 불명확)
const str = value + ""; // 문자열 변환 (관용적이지만 불명확)
const bool = !!value; // 불리언 변환
// 좋은 예: 명시적 변환
const count2 = Number("5"); // 명확
const str2 = String(value); // 명확
const bool2 = Boolean(value); // 명확
// 또는 더 의도를 드러내는 방법
const count3 = parseInt("5", 10);
const str3 = `${value}`;
const bool3 = value !== null && value !== undefined;
JSON 변환
// 객체 ↔ JSON 문자열
const obj = { name: "철수", age: 25, scores: [90, 85, 92] };
// 직렬화 (객체 → JSON 문자열)
const json = JSON.stringify(obj);
console.log(json); // '{"name":"철수","age":25,"scores":[90,85,92]}'
// 예쁘게 출력
console.log(JSON.stringify(obj, null, 2));
// 역직렬화 (JSON 문자열 → 객체)
const parsed = JSON.parse(json);
console.log(parsed.name); // "철수"
// JSON.stringify 제한
const withFn = { fn: () => {}, symbol: Symbol(), undef: undefined };
console.log(JSON.stringify(withFn)); // '{}' (함수, Symbol, undefined는 제외됨)