TIL. 53 타입 변환과 단축 평가

Minjae Choi·2022년 1월 9일
0

JavaScript

목록 보기
16/20

# 자바스크립트의 타입

  • 자바스크립트의 모든 값에는 타입이 있다.
  • 원시 타입: Number String Boolean Undefined Null
    • 데이터 복사가 일어날 때, 메모리 공간을 새로 확보해 독립적인 값을 저장한다.
  • 참조 타입: Object ( Array Function Regex 모두 객체에 포함된다. )
    • 데이터 복사가 일어날 때, 값 자체가 아닌 메모리의 주소를 참조한다.
    • 해당 주소의 값이 변경되면 함께 변경된다.
    // 아래는 원시 타입 예시
    let a = 10
    const b = a
    
    a = 20
    console.log(b)  // 10 --- a가 변경되어도 값이 바뀌지 않는다.
    
    // 아래는 참조 타입 예시
    const a = []
    const b = a
    
    a.push('hi')
    console,log(b)  // 'hi' --- a가 변경되면 값이 함께 변경된다.

# 타입 변환

  • 타입은 개발자의 의도에 따라 다른 타입으로 변환될 수 있다. 이렇게 의도적으로 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅이라 한다.
  • 반대로 개발자의 의도와는 상관없이 표현식 평가 도중 자바스크립트 엔진에 의해 암묵적으로 타입이 자동 변환되는 것을 암묵적 타입 변환 또는 타입 강제 변환이라 한다.
  • 원시 값은 변경 불가능한 값이며 변경할 수 없으며, 타입 변환은 기존 원시 값을 사용해 새로운 원시 값을 생성하는 것이다.
    const a = 10  // Number 10
    const b = a.toString()  // String '10'으로 명시적 타입 변환
    const c = a + ''  // String '10'으로 암묵적 타입 변환
    
    a.toString()
    console.log(a)  // Number 10.. 원시 값은 변형되지 않는다.
    
    const arr = []
    arr.push('10')
    console.log(arr)  // ['10'] 배열은 원시값이 아니므로 변형 가능
  • c 예시의 경우, 자바스크립트 엔진은 원시 값 a를 바탕으로 새로운 문자 ‘10’을 생성하고, 표현식을 평가한다. 이 때 암묵적으로 생성된 문자열 ‘10’은 a 변수에 재할당 되지 않는다.
  • 즉, 암묵적 타입 변환은 표현식 평가를 위한 조치이며 새로운 타입의 값을 만들고 사용한 후 버린다.
    a.toString()
    a + ''
    
    // 무조건 명시적 타입 변환이 좋다고 하는 것은 아니다.
    // 어떤 것이 좀 더 가독성이 있는지는 개발자의 판단에 맡긴다.

# 생각

  • 암묵적 타입 변환은 개발자의 의도가 담기지 않으므로 사용에 주의를 기울여야 한다. 그래서 타입스크립트를 쓰는가보다.. 정확한 타입을 지정하거나 좀 더 의도가 명확하게 명시적 타입 변환을 사용하면 좀 더 클린한 코드가 될 수 있을 것 같다.
  • 딥다이브에서는 암묵적 타입 변환이 더 가독성이 좋은 경우도 있다고 하지만, 개인적으로는 협업 측면에서 보면 메서드를 사용한 좀 더 명시적인 타입 변환이 의도를 파악하기 원활해 좋지 않을까 생각해본다.

# 암묵적 타입 변환


문자열 타입으로 변환

  • 암묵적 타입 변환 중 어떤 원리로 변환하는지 알아보겠다.
  • 먼저, 문자열 연결 연산자의 역할은 문자열 값을 만드는 것이다. 따라서 코드의 문맥상 모두 문자열 타입이어야 한다.
    // 모두 문자열 타입이어야 하는 문맥
    '10' + 2  // '102'
    true + '10'  // 'true10'
    
    // 모두 숫자 타입이어야 하는 문맥
    5 * '10'  // 50
    
    // 모두 불리언 타입이어야 하는 문맥
    !0  // true
    if (1) { }  // true
    
    // ES6에서 도입된 템플릿 리터럴의 경우에도 문자열 타입으로 암묵적 타입 변환을 한다.
    `1 + 1 = ${1 + 1}`  // '1 + 1 = 2'
  • 하지만 특정 경우에는 그대로의 값을 문자열로 변환하지는 않는다.
    ({}) + ''  // '[object Object]'
    
    Math + ''  // '[object Math]'
    
    [] + ''  // ''
    
    [10, 20] + ''  // '10, 20'
    
    Array + ''  // 'function Array() { [native code] }'

숫자 타입으로 변환의 경우

  • 산술 연산자의 피연산자 중에서 숫자 타입이 아닌 것을 숫자 타입으로 암묵적으로 변환한다. 이 때, 숫자 타입으로 변환할 수 없는 경우의 결과는 NaN이 된다.
  • 객체와 값이 들어있는 배열, 그리고 undefined의 경우 변환되지 않아 NaN이 된다.
    + ''  // 0
    + 'string'  // NaN
    
    + true  // 1
    + false  // 0
    
    + null  // 0
    + undefined  // NaN
    
    + []  // 0
    + {}  // NaN
    + [10, 20]  // NaN

불리언 타입으로 변환

  • if문이나 for문과 같은 제어문 또는 삼항 연산자의 조건식은 불리언 값, 즉 논리적 참/거짓으로 평가되어야 하는 표현식이다.
  • false undefined null NaN ‘’(빈 문자열)은 false로 평가되는 Falsy 값이다.
    if ('') console.log('1')
    if (true) console.log('2')
    if (0) console.log('3')
    if ('str') console.log('4')
    if (null) console.log('5')
    if ('0') console.log('6')
    
    // 위의 결과는? 정답은 2, 4, 6이다.

# 명시적 타입 변환


문자열 타입으로 변환

  • String 생성자 함수를 활용하는 방법
  • toString() 메서드를 활용하는 방법
  • 문자열 연결 연산자(암묵적 타입 변환)를 활용하는 방법
    String(1)  // '1'
    String(NaN)  // 'NaN'
    String(true)  // 'true'
    
    (1).toString()  // '1'
    (NaN).toString()  // 'NaN'
    (true).toString()  // 'true'

숫자 타입으로 변환

  • Number 생성자 함수를 활용하는 방법
  • parseInt parseFloat 함수를 사용하는 방법(문자열만 숫자 타입으로 변환 가능)
    • 단항 산술 연산자를 이용하는 방법(암묵적 타입 변환)
    • 산술 연산자를 이용하는 방법(암묵적 타입 변환)
    Number('0')  // 0
    Number('10.53')  // 10.53
    Number(true)  // 1
    Number(false)  // 0
    
    parseInt('0')  // 0
    parseInt('10.53')  // 10.53
    parseInt(true)  // NaN
    
    +'10.53'  // 10.53
    
    true * 2  // 2 (true는 1이기 때문)
    false * 1  // 0

불리언 타입으로 변환

  • Boolean 생성자 함수를 활용하는 방법
  • ! 부정 논리 연산자를 두 번 사용하는 방법
    Boolean('a')  // true
    Boolean('')  // false
    Boolean('false')  // true
    
    !!'a'  // true
    !!''  // false
    
    // 빈 문자열 '', 0, Nan, null, undefined인 경우 false로 처리된다.

# 단축 평가


논리 연산자를 사용한 단축 평가

  • 표현식 평가 도중에 평가 결과가 확정된 경우 나머지 평가 과정을 생략하는 것을 단축 평가라 한다.
  • 논리곱 연산자(&&) 또는 논리합 연산자(||) 표현식의 평가 결과는 불리언 값이 아닐 수도 있다. 그저 “언제나 어느 한쪽으로 평가된다".
  • 논리곱 연산자는 두 개의 값이 모두 true일 때 true의 값을 반환한다.
  • 논리합 연산자는 두 개의 값 중 하나만 true로 평가되어도 true의 값을 반환한다.
  • 아래 예시와 같이 논리합/논리곱 연산자는 피연산자를 타입 변환하지 않고 그대로 반환한다.
    // 'Dog'까지 평가해 보아야 아래 표현식을 평가할 수 있다.
    'Cat' && 'Dog'  // 'Dog'
    
    // 굳이 두 번째 값을 평가하지 않아도 아래 표현식을 평가할 수 있다.
    'Cat' || 'Dog'  // 'Cat'
    
    // 아래는 단축 평가가 따르는 규칙
    true || anything  // true
    false || anything  // anything
    true && anything  // anything
    false && anything  // false

단축 평가의 활용

  • if문에 대한 예시 코드
    let message = ''
    let value = true
    
    // 예시1 - if문으로 표현
    if (value) message = '완료'
    if (!value) message = '미완료'
    
    // 예시2 - 논리 연산자로 표현
    message = value && '완료'
    message = value || '미완료'  // value true 
    
    // 예시3 - if else문, 삼항 조건 연산자
    if (value) message = '완료'
    else message = '미완료'
    
    message = value ? '완료' : '미완료'
  • 변수의 값이 객체가 아니라 null 또는 undefined인 경우, 객체로 기대하고 프로퍼티를 참조하면 타입 에러가 발생한다.
  • 하지만 위 상황에서 단축 평가를 사용하면 에러가 발생하지 않는다.
    const obj = null
    
    const value = obj.value  // 타입 에러
    const value = obj && obj.value  // null
  • 함수를 호출할 때, 인수를 전달하지 않으면 매개변수에는 undefined가 할당된다. 이 때 단축 평가를 사용해 매개변수의 기본값을 설정해 undefined로 인해 발생할 수 있는 에러를 방지할 수 있다.
    function test(str) {
    	str = str || ''  // 이 단축 평가가 없다면 타입 에러
    	return str.length
    }
    test()  // 0
    
    // 아래는 ES6의 매개변수 기본값을 설정하는 방법
    function test(str = '') {
    	return str.length
    }

옵셔널 체이닝 연산자(?.)

  • ES11에서 도입되었으며 좌항의 값이 null 또는 undefined인 경우 undefined를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.
    const obj = null
    const value = obj?.value  // undefined
    
    // 하지만 아래처럼, null 또는 undefined가 아니면 우항 참조 진행
    const str = ''
    const length = str?.length  // 0 (false 값이지만 우항 참조)

null 병합 연산자(??)

  • 옵셔널 체이닝 연산자와 마찬가지로 ES11에서 도입되었다.
  • 좌항의 값이 null 또는 undefined인 경우 우항의 값을 반환하고, 그렇지 않으면 좌항의 값을 반환한다.
  • 변수에 기본값을 설정할 때 유용하다.
    // 아래는 기본값을 논리합 연산자를 활용했을 때,
    // false가 기준이므로 ''나 0이 기본값으로 설정할 수 없다.
    const str = '' || 'default string'  // 'default string'
    
    // null 병합 연산자를 이용하면 '', 0으로 기본값 설정이 가능하다.
    const str = '' ?? 'default string'  // ''
    const str = null ?? 'default string'  // 'default string'

0개의 댓글