https://poiemaweb.com/js-type-coercion
1. 타입 변환이란?
자바스크립트의 모든 값은 타입을 가지며 변환 될 수 있다.
- 개발자의 의도 -> 명시적 타입 변환(Explicit coercion) / 타입 캐스팅(Type casting)
- 자바스크립가 자동 ->암묵적 타입 변환(Implicit coercion) / 타입 강제 변환(Type coercion)
2. 암묵적 타입 변환
- 자바스크립트 엔진이 표현식을 에러없이 평가하기 위해 기존 값을 바탕으로 새로운 타입의 값을 만들어 단 한번 사용하고 지워 버린다.
- 코드에서 암묵적 타입 변환이 발생하는지, 발생한다면 어떻게 평가될 것인지 예측 가능해야 한다.
- 예측한 내용이 결과와 일치하지 않는다면 버그를 생산할 가능성이 높아진다.
- 명시적 타입 변환보다 암묵적 타입 변환이 가독성 면에서 더 좋을 수도 있다.
// 표현식이 모두 문자열 타입이여야 하는 컨텍스트
'10' + 2 // '102'
`1 * 10 = ${ 1 * 10 }` // "1 * 10 = 10"
// 표현식이 모두 숫자 타입이여야 하는 컨텍스트
5 * '10' // 50
// 표현식이 불리언 타입이여야 하는 컨텍스트
!0 // true
if (1) { }
자바스크립트 엔진은 표현식을 평가할 때,
문맥(Context)을 고려하여 에러를 발생시키지 않도록 암묵적 타입 변환을 실행한다.
암묵적 타입 변환의 대상 : 피연산자 , 표현식
2.1. 문자열 타입으로 변환
문자열 연결 연산자 : +
숫자 , 불리언 , null , undefined , 심볼, 객체 타입 + '문자' // '문자열 타입'
+ 연산자는 피연산자 중 하나 이상이 문자열이므로 문자열 연결 연산자로 동작한다.
문자열 연결 연산자(+) 의 피연산자 (1 과 '2') 는 문맥, 즉 컨텍스트 상 문자열 타입이여야 한다.
자바스크립트 엔진은 문자열 연결 연산자(+) 의 피연산자 (1 과 '2') 를 문자열 타입으로 암묵적 타입 변환한다.
단 + 연산자 앞에 피연산자가 없을 경우 2.2의 산술연산자로 동작한다.
2.2. 숫자 타입으로 변환
산술 연산자 : - , * , / , %
비교 연산자 : >
10 + '2' // 102
10 - '2' // 8
10 * '2' // 20
10 / '2' // 5
10 % '2' // 0
'1' > 0 // true
- true -> 1
- false , 빈 문자열(‘’), 빈 배열([]), null -> 0
- 숫자 타입으로 변환할 수 없는 경우 NaN 반환
- 객체와 빈 배열이 아닌 배열, undefined -> NaN
// 문자열 타입
+'' // 0
+'0' // 0
+'1' // 1
+'string' // NaN
// 불리언 타입
+true // 1
+false // 0
// null 타입
+null // 0
// undefined 타입
+undefined // NaN
// 심볼 타입
+Symbol() // TypeError: Cannot convert a Symbol value to a number
// 객체 타입
+{} // NaN
+[] // 0
+[10, 20] // NaN
+(function(){}) // NaN
2.3. 불리언 타입으로 변환
제어문의 조건식 , if , for
if 문이나 for 문과 같은 제어문의 조건식(conditional expression)은 불리언 값, 즉 논리적 참, 거짓을 반환해야 하는 표현식이다.
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
불리언 값으로 평가되어야 할 컨텍스트에서 false로 평가되는 Falsy 값
- false
- undefined
- null
- 0, -0
- NaN
- ’’ (빈문자열)
이외의 값은 모두 true로 평가
false 의 경우 토글 기능 만들때 주로 사용하기도 한다.
간단하게 만들어봤는데
var toggle = true;
function toggle_btn(){
toggle = !toggle;
}
toggle_btn()
console.log('toggle:', toggle) // toggle: false
toggle_btn()
console.log('toggle:', toggle) // toggle: true
toggle_btn()
console.log('toggle:', toggle) // toggle: false
똑같은 코드를 반복하는데 번갈아서 다른 결과가 나오게 된다.
3. 명시적 타입 변환
개발자의 의도에 의해 명시적으로 타입을 변경
- 래퍼 객체(Wrapper Object) 생성자 함수를 new 연산자 없이 호출하는 방법
- 자바스크립트에서 제공하는 빌트인 메소드를 사용하는 방법,
- 암묵적 타입 변환을 이용하는 방법이 있다.
3.1 문자열 타입으로 변환
문자열 타입이 아닌 값을 문자열 타입으로 변환하는 방법은 아래와 같다.
- String 생성자 함수를 new 연산자 없이 호출하는 방법
- Object.prototype.toString 메소드를 사용하는 방법
- 문자열 연결 연산자를 이용하는 방법
// 1. String 생성자 함수를 new 연산자 없이 호출하는 방법
// 숫자 타입 => 문자열 타입
console.log(String(1)); // "1"
console.log(String(NaN)); // "NaN"
console.log(String(Infinity)); // "Infinity"
// 불리언 타입 => 문자열 타입
console.log(String(true)); // "true"
console.log(String(false)); // "false"
// 2. Object.prototype.toString 메소드를 사용하는 방법
// 숫자 타입 => 문자열 타입
console.log((1).toString()); // "1"
console.log((NaN).toString()); // "NaN"
console.log((Infinity).toString()); // "Infinity"
// 불리언 타입 => 문자열 타입
console.log((true).toString()); // "true"
console.log((false).toString()); // "false"
// 3. 문자열 연결 연산자를 이용하는 방법
// 숫자 타입 => 문자열 타입
console.log(1 + ''); // "1"
console.log(NaN + ''); // "NaN"
console.log(Infinity + ''); // "Infinity"
// 불리언 타입 => 문자열 타입
console.log(true + ''); // "true"
console.log(false + ''); // "false"
3.2 숫자 타입으로 변환
숫자 타입이 아닌 값을 숫자 타입으로 변환하는 방법은 아래와 같다.
- Number 생성자 함수를 new 연산자 없이 호출하는 방법
- parseInt, parseFloat 함수를 사용하는 방법(문자열만 변환 가능)
- 단항 연결 연산자를 이용하는 방법
- 산술 연산자를 이용하는 방법
- .toNumber() 는 없음
// 1. Number 생성자 함수를 new 연산자 없이 호출하는 방법
// 문자열 타입 => 숫자 타입
console.log(Number('0')); // 0
console.log(Number('-1')); // -1
console.log(Number('10.53')); // 10.53
// 불리언 타입 => 숫자 타입
console.log(Number(true)); // 1
console.log(Number(false)); // 0
// 2. parseInt, parseFloat 함수를 사용하는 방법(문자열만 변환 가능)
// 문자열 타입 => 숫자 타입
console.log(parseInt('0')); // 0
console.log(parseInt('-1')); // -1
console.log(parseFloat('10.53')); // 10.53
// 3. + 단항 연결 연산자를 이용하는 방법
// 문자열 타입 => 숫자 타입
console.log(+'0'); // 0
console.log(+'-1'); // -1
console.log(+'10.53'); // 10.53
// 불리언 타입 => 숫자 타입
console.log(+true); // 1
console.log(+false); // 0
// 4. * 산술 연산자를 이용하는 방법
// 문자열 타입 => 숫자 타입
console.log('0' * 1); // 0
console.log('-1' * 1); // -1
console.log('10.53' * 1); // 10.53
// 불리언 타입 => 숫자 타입
console.log(true * 1); // 1
console.log(false * 1); // 0
이전 글에서 자바스크립트는 하나의 숫자 타입만 존재한다.
-> float , int 를 쓰는거아닌가?
-> typeof 를 찍어보면 number 로 나온다.
3.3 불리언 타입으로 변환
불리언 타입이 아닌 값을 불리언 타입으로 변환하는 방법은 아래와 같다.
- Boolean 생성자 함수를 new 연산자 없이 호출하는 방법
- ! 부정 논리 연산자를 두번 사용하는 방법
// 1. Boolean 생성자 함수를 new 연산자 없이 호출하는 방법
// 문자열 타입 => 불리언 타입
console.log(Boolean('x')); // true
console.log(Boolean('')); // false
console.log(Boolean('false')); // true
// 숫자 타입 => 불리언 타입
console.log(Boolean(0)); // false
console.log(Boolean(1)); // true
console.log(Boolean(NaN)); // false
console.log(Boolean(Infinity)); // true
// null 타입 => 불리언 타입
console.log(Boolean(null)); // false
// undefined 타입 => 불리언 타 입
console.log(Boolean(undefined)); // false
// 객체 타입 => 불리언 타입
console.log(Boolean({})); // true
console.log(Boolean([])); // true
// 2. ! 부정 논리 연산자를 두번 사용하는 방법
// 문자열 타입 => 불리언 타입
console.log(!!'x'); // true
console.log(!!''); // false
console.log(!!'false'); // true
// 숫자 타입 => 불리언 타입
console.log(!!0); // false
console.log(!!1); // true
console.log(!!NaN); // false
console.log(!!Infinity); // true
// null 타입 => 불리언 타입
console.log(!!null); // false
// undefined 타입 => 불리언 타입
console.log(!!undefined); // false
// 객체 타입 => 불리언 타입
console.log(!!{}); // true
console.log(!![]); // true
5. 단축 평가
console.log(true && false) // false
console.log(false && true) // false
console.log(true && true) // true
console.log('Cat' && 'Dog') // “Dog”
논리곱 연산자 &&는 두개의 피연산자가 모두 true로 평가될 때 true를 반환한다.
왼쪽이 true 일 경우 오른쪽의 결과에 따라 true / false 가 정해진다.
왼쪽이 false 일 경우 더이상 연산 할 필요없이 false 가 된다.
- 'Cat' 과 'Dog' 의 경우 왼쪽의 'Cat' 는 true 이며 오른쪽의 결과에 따라 true / false 가 정해진다.
- 'Dog' 가 결과를 결정하는 더 중요한 값이 되며 true 이므로 'Dog' 가 나오게 된다.
console.log(true || false) // true
console.log(false || true) // true
console.log(false || false) // false
console.log('Cat' || 'Dog') // 'Cat'
논리합 연산자 || 는 두개의 피연산자 중 하나가 true로 평가될 때 true 를 반환한다.
왼쪽이 true 일 경우 더 이상 연산할 필요없이 true 가 된다.
왼쪽이 false 일 경우 오른쪽의 결과에 따라 true / false 가 정해진다.
- 'Cat' 과 'Dog' 의 경우 왼쪽의 'Cat' 이 true 이며 더 이상 연산할 필요없이 true 가 된다.
- 오른쪽의 값은 표현식에 영향을 주지 않는다.
이와 같이 논리 평가를 결정한 피연산자의 평가 결과를 그대로 반환한다.
이를 단축 평가(Short-Circuit evaluation)라 부른다.
// 논리합(||) 연산자
'Cat' || 'Dog' // 'Cat'
false || 'Dog' // 'Dog'
'Cat' || false // 'Cat'
// 논리곱(&&) 연산자
'Cat' && 'Dog' // Dog
false && 'Dog' // false
'Cat' && false // false
유용한 상황
- 객체가 null인지 확인하고 프로퍼티를 참조할 때
var elem = null;
console.log(elem.value); // TypeError: Cannot read property 'value' of null
console.log(elem && elem.value); // null
// 단축 평가를 사용한 매개변수의 기본값 설정
function getStringLength(str) {
str = str || '';
return str.length;
}
getStringLength(); // 0
getStringLength('hi'); // 2
// ES6의 매개변수의 기본값 설정
function getStringLength(str = '') {
return str.length;
}
getStringLength(); // 0
getStringLength('hi'); // 2
함수를 호출할 때 인수를 전달하지 않으면 매개변수는 undefined를 갖는다.
getStringLength() 함수 호출시, '' (빈 문자열)을 넣어 주고 0을 return 하여 에러가 나지 않게 해준다.
해당 코드가 없다면 TypeError 가 발생한다.