🤓 모던 자바스크립트 Deep Dive 책을 통해서 자바스크립트를 공부중입니다.
개발자가 의도적으로 값의 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅이라고 합니다.
var x = 10;
// 명시적 타입 변환
// 숫자를 문자열로 타입 캐스팅
var str = x.toString();
console.log(typeof str, str); // string 10
// x 변수의 값이 변경된 것은 아님
console.log(typeof x, x); // number 10
개발자의 의도와 상관없이 표현식을 평가하는 도중에 자바스크립트 엔진에 의해 암묵적으로 타입이 자동변환되기도 하는데, 이를 암묵적 타입 변환 또는 타입 강제 변환이라고 합니다.
var str = x + '';
console.log(typeof str, str); // string 10
//x 변수의 값이 변경된 것은 아님
console.log(typeof x, x); // number 10
암묵적 타입 변환은 기존 변수 값을 재할당하여 변경하는 것이 아닙니다. 자바스크립트 엔진은 표현식을 에러없이 평가하기 위해 피연산자의 값을 암묵적 타입 변환해 새로운 타입의 값을 만들어 단 한 번 사용하고 버립니다.
명시적 타입 변환이나 암묵적 타입 변환이 기존 원시값을 직접 변경하는 것은 아닙니다. 타입 변환이란 기존 원시 값을 사용해 다른 타입의 새로운 원시 값을 생성하여 단 한 번 사용하는 것입니다.
// 피연산자가 모두 문자열 타입이어야 하는 문맥
'10' + 2 // '102'
// 피연산자가 모두 숫자 타입이어야 하는 문맥
5 * '10' // 50
// 피연산자 또는 표현식이 불리언 타입이어야 하는 문맥
!0 // true
if (1) {}
위의 예제처럼 표현식을 평가할 때 코드의 문맥에 부합하지 않는 다양한 상황이 발생할 수 있습니다. 이때 자바스크립트는 가급적 에러를 발생시키지 않도록 암묵적 타입 변환을 통해 표현식을 평가합니다.
1 + '2' // '12'
위 예제의 +
연산자는 피연산자 중 하나 이상이 문자열이므로 문자열 연결 연산자로 동작합니다. 문자열 연결 연산자의 역할은 문자열 값을 만드는 것이기 때문에 문자열 연결 연산자의 모든 피연산자는 코드의 문맥상 문자열 타입이어야 합니다.
자바스크립트 엔진은 문자열 연결 연산자 표현식을 평가하기 위해 문자열 연결 연산자의 피연산자 중에서 문자열 타입이 아닌 피연산자를 문자열 타입으로 암묵적 타입 변환합니다.
연산자 표현식의 피연산자만이 암묵적 타입 변환의 대상이 되는 것은 아닙니다. ES6에서 도입된 템플릿 리터럴의 표현식 삽입은 표현식 평가 결과를 문자열 타입으로 암묵적 타입 변환합니다.
`1 + 1 = ${1 + 1}` // '1 + 1 = 2'
자바스크립트 엔진은 문자열 타입 아닌 값을 문자열 타입으로 암묵적 타입 변환을 수행할 때 다음과 같이 동작합니다.
0 + '' // "0"
-0 + '' // "0"
1 + '' // "1"
-1 + '' // "-1"
NaN + '' // "NaN"
Infinity + '' // "Infinity"
-Infinity + '' // "-Infinity"
true + '' // "true"
false + '' // "false"
null + '' // "null"
undefined + '' // "undefined"
(Symbol()) + '' // TypeError: Cannot convert a Symbol value to a string
({}) + '' // "[object Object]"
Math + '' // "[object Math]"
[] + '' // ""
[10, 20] + '' // "10, 20"
(function(){}) + '' // "function(){}"
Array + '' // "function Array() { [native code] }"
1 - '1' // 0
1 * '10' // 10
1 / 'one' //NaN
위 예제에서 사용한 연산자는 모두 산술 연산자입니다. 산술 연산자의 역할은 숫자 값을 만드는 것이기 때문에 산술 연산자의 모든 피연산자는 코드 문맥상 숫타 타입이어야 합니다.
자바스크립트 엔진은 산술 연산자 표현식을 평가하기 위해 산술 연산자의 피연산자 중에서 숫자 타입이 아닌 피연산자를 숫자 타입으로 암묵적 타입 변환합니다. 이때 피연산자를 숫자 타입으로 변환할 수 없는 경우는 산술 연산을 수행할 수 없으므로 표현식의 평과 결과는 NaN
이 됩니다.
'1' > 0 // true
자바스크립트 엔진은 비교 연산자 표현식을 평가하기 위해 비교 연산자의 피연산자 중에서 숫자 타입이 아닌 피연산자를 숫자 타입으로 암묵적 타입 변환합니다.
+
단항 연산자는 피연산자가 숫자 타입의 값이 아니면 숫자 타입의 값으로 암묵적 타입 변환을 수행합니다.
+'' // 0
+'0' // 0
+'1' // 1
+'string' // NaN
+true // 1
+false // 0
+null // 0
+undefined // NaN
+Symbol() // TypeError: Cannot convert a Symbol value to a number
+{} // NaN
+[] // 0
+[10, 20] // NaN
+(function(){}) // NaN
빈 문자열(''
), 빈 배열([]
), null
, false
는 0
으로 true
는 1
로 변환됩니다. 객체와 빈 배열이 아닌 배열, undefined는 변환되지 않아 NaN이 됩니다.
if ('') consoel.log(x);
if
문이나 for
문과 같은 제어문 또는 삼항 조건 연산자의 조건식은 불리언 값(논리적 참/ 거짓으로 평가 되는 값)으로 평가 되어야 하는 표현식입니다. 자바스크립트 엔진은 조건식의 평가 결과를 불리언 타입으로 암묵적 타입 변환 합니다.
if ('') console.log('1');
if (true) console.log('2');
if (0) console.log('3');
if ('str') console.log('4');
if (null) console.log('5');
// 2 4
자바스크립트 엔진은진은 불리언 타입이 아닌 값을 Truth 값 또는 Falsy 값으로 구분합니다. 즉, 제어문의 조건식과 같이 불리언 값으로 평가되어야 할 문맥맥에서 Truthy 값은 true로, Flasy값은 false로 암묵적 타입 변환됩니다.
if (!false) console.log(false + ' is falsy value');
if (!undefined) console.log(undefined + ' is falsy value');
if(!null) console.log(null + ' is falsy value');
if (!0) console.log(0 + ' is falsy value');
if (!NaN) console.log(NaN + ' is flasy value');
if (!'') console.log('' + ' is falsy value');
function isFalsy(v) {
return !v;
}
function isTruthy(v) {
return !!v;
}
// 모두 true 반환
isFalsy(false);
isFalsy(undefined);
isFalsy(null);
isFalsy(0);
isFalsy(NaN);
isFalsy('');
// 모두 true 반환
isTruthy(true);
isTruthy('0'); // 빈 문자열이 아닌 문자열은 Truthy값
isTruthy({});
isTruthy([]);
함수
함수란 어떤 작업을 수행하는데 필요한 문들의 집합을 정의한 코드 블록입니다. 함수는 이름과 매개변수를 가지며, 필요할 때 호출해 코드 블록에 담긴 문들을 일괄적으로 실행할 수 있습니다.
개발자의 의도에 따라 명시적으로 타입을 변경하는 방법으로는 표준 빌트인 생성자 함수를 new
연산자 없이 호출하는 방법과 빌트인 메서드를 사용하는 방법, 암묵적 타입 변환을 이용하는 방법이 있습니다.
표준 빌트인 생성자 함수와 빌트인 메서드
표준 빌트인 생성자 함수와 표준 빌트인 메서드는 자바스크립트에서 기본 제공하는 함수입니다. 표준 빌트인 생성자 함수는 객체를 생성하기 위한 함수이며 new 연산자와 함께 호출합니다. 표준 빌트인 메서드는 자바스크립트에서 기본 제공하는 빌트인 객체의 메서드입니다.
// 숫자 타입 => 문자열 타입
Stiring(1); // "1"
String(NaN); // "NaN"
string(Infinity); // "Infinity"
// 불리언 타입 => 문자열 타입
String(true); // "true"
String(false); // "false"
// 숫자 타입 => 문자열 타입
(1).toString(); // "1"
(NaN).toString(); // "NaN"
(Infinity).toString(); // "Infinity"
// 불리언 타입 => 문자열 타입
(true).toString(); // "true"
(false).toString(); // "false"
// 숫자 타입 => 문자열 타입
1 + '' // "1"
NaN + '' // "NaN"
Infinity + '' // "Infinity"
// 불리언 타입 => 문자열 타입
true + ''; // true
false + ''; // false
Number
생성자 함수를 new
연산자 없이 호출하는 방법// 문자열 타입 => 숫자 타입
Number('0'); // 0
Number('-1'); // -1
Number('10.53'); // 10.53
// 불리언 타입 => 숫자 타입
Number(true); // 1
Number(false); // 0
parseInt
parseFloat
함수를 사용하는 방법// 문자열 타입 => 숫자 타입
parseInt('0'); // 0
parseInt('-1'); // -1
parseFloat('10.53'); // 10.53
+
단항 산술 연산자를 이용하는 방법// 문자열 타입 => 숫자 타입
+'0'; // 0
+'-1'; // -1
+'10.53'; // 10.53
//불리언 타입 => 숫자 타입
+true; // 1
+false; // 0
*
산술 연산를 이용하는 방법// 문자열 타입 => 숫자 타입
'0' * 1; // 0
'-1' * 1; // -1
'10.53' * 1; // 10.53
// 불리언 타입 => 숫자 타입
true * 1; // 1
false * 1; // 0
Boolean
생성자 함수를 new
연산자 없이 호출하는 방법// 문자열 타입 => 불리언 타입
Boolean('x'); // true
Boolean(''); // false
Boolean('false'); // true
// 숫자 타입 => 불리언 타입
Boolean(0); // false
Boolean(1); // true
Boolean(NaN); // false
Boolean(Infinity); // true
// null 타입 => 불리언 타입
Boolean(null); // false
// undefined 타입 => 불리언 타입
Boolean(undefined); // false
// 객체 타입 => 불리언 타입
Boolean({}); // true
Boolean([]); // true
!
부정 논리 연산자를 두 번 사용하는 방법// 문자열 타입 => 불리언 타입
!!'x'; // true
!!''; // false
!!'false'; // true
// 숫자 타입 => 불리언 타입
!!0; // false
!!1; // true
!!NaN; // false
!!Infinity; // true
// null 타입 => 불리언 타입
!!undefined; // false
// 객체 타입 => 불리언 타입
!!{}; // true
!![]; // true