JavaScript에서 값은 서로 다른 타입일 수 있어요. 변수의 타입은 명시적인 _타입 변환_으로 바꿀 수 있어요. 그 외에도 JavaScript는 상황이 요구하면 타입 강제 변환(암시적 타입 변환)도 수행해요.
JavaScript에는 다른 많은 언어처럼 (다른) 타입으로 캐스팅하는 구문이 없지만, 대신 몇 가지 내장 도우미를 사용할 수 있어요.
특히 전역 객체인 Boolean, Number, String을 함수처럼 사용해서 값을 해당 타입으로 변환할 수 있어요.
Boolean(value)를 사용하면 어떤 값이든 불리언으로 변환할 수 있어요.
어떻게 그렇게 될까요?
false로 변환되는 값들의 집합이 정해져 있는데, 이런 값을 _falsy_라고 해요.
가장 중요한 것은 false, 0, 빈 문자열, null, undefined, NaN이 falsy라는 점이에요.
MDN의 "Falsy" 문서에서 전체 목록을 볼 수 있어요.
그 외의 모든 값에 대해서는 Boolean이 true를 반환해요.
이런 값을 _truthy_라고 해요.
Boolean(-1);
// => true
Boolean(0);
// => false
Boolean(' ');
// => true
Boolean('');
// => false
참고로, 방금 설명한 규칙 때문에 '0', 'false', [], {}는 JavaScript에서 truthy예요.
Number(value)는 값을 숫자로 변환할 때 사용할 수 있어요.
문자열의 앞과 뒤에 있는 공백은 무시되고, 빈 문자열은 0으로 변환돼요.
원시 값이 아닌 값이나 숫자를 나타내지 않는 문자열을 변환하려고 해도 오류가 발생하지 않아요.
대신 결과는 NaN(숫자가 아님)이에요.
Number(' -12.34 ');
// => -12.34
Number('1,2');
// => NaN
Number('1 2');
// => NaN
Number('');
// => 0
Number('10e3');
// => 10000
Number({ key: '123' });
// => NaN
아래에서 다른 원시 값들에 대해 Number가 반환하는 값을 볼 수 있어요.
Number(true);
// => 1
Number(false);
// => 0
Number(null);
// => 0
Number(undefined);
// => NaN
참고로, 마지막 예제와 달리 인자 없이 호출한 Number()는 0을 반환하도록 정의돼 있어요.
JavaScript는 parseInt와 parseFloat 함수도 제공해요.
이 함수들은 어떤 문자열을 숫자로 변환할 수 있는지에 대해 더 느슨한 규칙을 적용해요.
그래서 예상치 못한 결과를 피하려면 변환 함수로는 Number를 사용하는 게 좋아요.
parseInt('123a45');
// => 123
Number('123a45');
// => NaN
String(value)로 값을 문자열로 변환할 수 있어요.
원시 값이라면 결과는 예상하는 그대로예요.
String(12.34);
// => '12.34'
String(false);
// => 'false'
String(null);
// => 'null'
String(undefined);
// => 'undefined'
배열의 경우, String 함수는 각 원소에 문자열 변환을 적용한 뒤 그 결과를 쉼표로 이어 붙여요.
구분자를 직접 지정하는 등 join 메서드를 직접 사용할 수도 있어요.
다만 이 경우 null과 undefined는 빈 문자열로 변환돼요.
String([42, null, true, 'abc']);
// => '42,,true,abc'
객체의 경우, 기본적으로 String은 별로 도움이 되지 않는 텍스트를 반환해요.
String({ key: 'value' });
// => '[object Object]'
toString 메서드를 제공하는 식으로 변환 동작을 직접 바꿀 수도 있어요.
javascript.info의 "객체를 원시 값으로 변환하기" 섹션에서 자세한 내용을 설명해요.
객체와 배열을 더 나은 문자열로 표현하는 또 다른 흔한 방법은 JSON 인코딩을 사용하는 거예요.
JSON.stringify로 문자열로 변환하고, JSON.parse로 다시 객체나 배열로 되돌릴 수 있어요.
const obj = {
name: 'Gilda Guerra',
address: {
city: 'Goiânia',
},
};
JSON.stringify(obj);
// => '{"name":"Gilda Guerra","address":{"city":"Goiânia"}}'
특정한 문맥에서 JavaScript는 어떤 문을 평가하기 전에 값을 다른 데이터 타입으로 자동 변환해요. 이렇게 암시적으로 이루어지는 변환을 _타입 강제 변환_이라고 해요.
값이 불리언 문맥에서 사용되면, JavaScript는 Boolean 함수와 같은 규칙을 적용해서 값을 암시적으로 변환해요.
if 문의 조건이 불리언이 아니면, 조건이 충족되는지 아닌지를 판단하기 위해 강제 변환이 적용돼요.
삼항 연산자 ?의 첫 번째 피연산자에도 같은 규칙이 적용돼요.
const num = 0;
if (num) {
// this block is NOT executed because 0 is falsy
}
const name = 'Jin';
name ? 'name was provided' : 'no name provided';
// => 'name was provided'
논리 NOT 연산자 !의 피연산자도 NOT 연산이 적용되기 전에 불리언으로 강제 변환돼요.
const name = '';
!name;
// => true
이런 동작의 결과로 !!value는 Boolean(value)와 같은 효과를 내요.
그래도 가독성을 위해 Boolean을 사용하는 게 좋아요.
JavaScript는 논리 AND(&&)와 OR(||) 연산자의 피연산자에도 강제 변환을 적용해요.
하지만 표현식의 결과가 반드시 불리언인 것은 아니에요.
원래 피연산자 중 하나를 반환해요(논리 연산자에 관한 MDN 문서 참고).
null || 'hello';
// => 'hello'
덧셈 연산자 +를 원시 값에 사용하는데 피연산자 하나가 문자열이면, 다른 하나도 문자열로 강제 변환돼요.
변환 논리는 String 함수를 사용할 때와 같아요.
그다음 두 문자열이 이어 붙여져요.
let name;
'hello ' + name;
// => 'hello undefined'
문자열이 아닌 값이 템플릿 문자열에 들어 있을 때도 같은 암시적 변환이 일어나요.
const degrees = 23;
`It is ${degrees} °C`;
// => 'Is is 23 °C.';
많은 연산자가 위에서 설명한 Number 함수의 논리에 따라 (필요하다면) 피연산자를 숫자로 강제 변환해요.
+(문자열이 포함되지 않은 경우), -, *, /, %, **
+, -
>, >=, <, <=
|, &, ^, ~
이 연산자들에 대한 더 자세한 내용은 MDN 연산자 목록을 참고해요.
피연산자가 문자열일 가능성이 있다면, 실수를 피하기 위해 항상 Number 함수로 명시적으로 변환하는 게 가장 좋아요.
'1' + '2';
// => '12'
// addition operator in string context as explained above
Number('1') + Number('2');
// => 3
가끔 단항 플러스 연산자로 문자열을 숫자로 강제 변환하는 코드를 보게 될 거예요.
이 방법은 명시적인 Number 호출보다 읽기 훨씬 어렵기 때문에 권장하지 않아요.
const value = '42';
+value;
// => 42
Number(value);
// => 42
느슨한 동등 및 부등 연산자 ==/!=를 사용할 때도 숫자로의 암시적 변환이 자주 일어나요.
하지만 이 연산자들의 정확한 논리는 꽤 복잡해요(느슨한 동등성에 관한 MDN 문서 참고).
결과를 예측하기 어렵고, 때로는 예상과 다른 값이 나와요.
이런 암시적 변환을 피하려면 엄격한 동등/부등 연산자 ===/!==를 사용해요.