JavaScript

9. Type coercion 타입 변환과 단축 평가

js0616 2024. 7. 8. 05:43

https://poiemaweb.com/js-type-coercion

 

Type coercion | PoiemaWeb

자바스크립트의 모든 값은 타입이 있다. 값의 타입은 다른 타입으로 개발자에 의해 의도적으로 변환할 수 있다. 또는 자바스크립트 엔진에 의해 암묵적으로 자동 변환될 수 있다. 개발자에 의해

poiemaweb.com

 

 

 

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' // "12"
 

 

+ 연산자는 피연산자 중 하나 이상이 문자열이므로 문자열 연결 연산자로 동작한다. 

문자열 연결 연산자(+) 의 피연산자 (1 과 '2') 는 문맥, 즉 컨텍스트 상 문자열 타입이여야 한다.
자바스크립트 엔진은 문자열 연결 연산자(+) 의 피연산자 (1 과 '2') 를 문자열 타입으로 암묵적 타입 변환한다.

 

 

단 + 연산자 앞에 피연산자가 없을 경우  2.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 가 된다.

 

  1. 'Cat' 과 'Dog' 의 경우 왼쪽의 'Cat' 는 true 이며 오른쪽의 결과에 따라 true / false 가 정해진다.
  2.  '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 가 정해진다.

 

  1. 'Cat' 과 'Dog' 의 경우 왼쪽의 'Cat' 이 true 이며 더 이상 연산할 필요없이 true 가 된다.
  2. 오른쪽의 값은 표현식에 영향을 주지 않는다.

 

이와 같이 논리 평가를 결정한 피연산자의 평가 결과를 그대로 반환한다.

이를 단축 평가(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

 

 

 

  • 함수의 인수(argument)를 초기화할 때
// 단축 평가를 사용한 매개변수의 기본값 설정
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  하여 에러가 나지 않게 해준다.

 

 
    str = str || ''
 

 

 

해당 코드가 없다면 TypeError 가 발생한다.