Post

[모던 자바스크립트 Deep Dive]09장 타입 변환과 단축 평가

9.1 타입 변환이란?

  • 명시적 타입 변환(explicit coercion) 또는 타입 캐스팅(type casting)
    • 개발자가 의도적으로 값의 타입을 변환
  • 암묵적 타입 변환(implicit coercion) 또는 강제 변환(type coercion)
    • 개발자의 의도와는 상관 없이 표현식을 평가하는 중 자바스크립트가 암묵적으로 타입을 변환
  • 타입 변환은 기존 원시 값을 직접 변경하지 않는다.
    • 원시 값은 변경 불가능한 값(immutable value)이다.

9.2 암묵적 타입 변환

9.2.1 문자열 타입으로 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 숫자 타입
0 + ''         // -> "0"
-0 + ''        // -> "0"
1 + ''         // -> "1"
-1 + ''        // -> "-1"
NaN + ''       // -> "NaN"
Infinity + ''  // -> "Infinity"
-Infinity + '' // -> "-Infinity"

// 불리언 타입
true + ''  // -> "true"
false + '' // -> "false"

// null 타입
null + '' // -> "null"

// undefined 타입
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] }"
  • 자바스크립트 엔진은 문자열 연결 연산자의 피연산자 중 문자열 타입이 아닌 것을 문자열 타입으로 암묵적 타입 변환
    • 리터럴의 표현식 삽입은 평가 결과를 문자열 타입으로 암묵적 타입 변환

9.2.2 숫자 타입으로 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 문자열 타입
+"" + // -> 0
  "0" + // -> 0
  "1" + // -> 1
  "string" + // -> NaN
  // 불리언 타입
  true + // -> 1
  false + // -> 0
  // null 타입
  null + // -> 0
  // undefined 타입
  undefined + // -> NaN
  // 심벌 타입
  Symbol() + // -> ypeError: Cannot convert a Symbol value to a number
  // 객체 타입
  {} + // -> NaN
  [] + // -> 0
  [10, 20] + // -> NaN
  function () {}; // -> NaN
  • 자바스크립트 엔진은 산술 연산자 표현식과 비교 연산자 표현식을 평가하기 위해 피연산자 중 숫자 타입이 아닌 것을 숫자 타입으로 암묵적 타입 변환

    1
    2
    3
    4
    5
    
    1 - "1"; // -> 0
    1 * "10"; // -> 10
    1 / "one"; // -> NaN
    
    "1" > 0; // -> true
    
    • 숫자 타입으로 변환할 수 없는 경우 평가 결과는 NaN

9.2.3 불리언 타입으로 변환

  • 자바스크립트 엔진은 조건식의 평가 결과를 Truthy 값 또는 Falsy 값으로 구분하여 암묵적 타입 변환
  • Falsy 값
    • false
    • undefined
    • null
    • 0, -0
    • NaN
    • ‘’
  • Truthy 값
    • {}, []를 포함하여 그냥 Falsy 값 외의 모든 값

9.3 명시적 타입 변환

  • 표준 빌트인 생성자 함수
    • 자바스크립트에서 기본 제공
    • 객체를 생성하기 위한 함수
    • new 연산자와 함께 호출
  • 표준 빌트인 메서드
    • 자바스크립트에서 기본 제공
    • 빌트인 객체의 메서드

9.3.1 문자열 타입으로 변환

  1. String 생성자 함수를 new 연산자 없이 호출하는 방법

    1
    2
    3
    4
    5
    6
    7
    
    // 숫자 타입 => 문자열 타입
    String(1); // -> "1"
    String(NaN); // -> "NaN"
    String(Infinity); // -> "Infinity"
    // 불리언 타입 => 문자열 타입
    String(true); // -> "true"
    String(false); // -> "false"
    
  2. Object.prototype.toString 메서드를 이용하는 방법

    1
    2
    3
    4
    5
    6
    7
    
    // 숫자 타입 => 문자열 타입
    (1).toString(); // -> "1"
    NaN.toString(); // -> "NaN"
    Infinity.toString(); // -> "Infinity"
    // 불리언 타입 => 문자열 타입
    true.toString(); // -> "true"
    false.toString(); // -> "false"
    
  3. 문자열 연결 연산자를 이용하는 방법

    1
    2
    3
    4
    5
    6
    7
    
    // 숫자 타입 => 문자열 타입
    1 + ""; // -> "1"
    NaN + ""; // -> "NaN"
    Infinity + ""; // -> "Infinity"
    // 불리언 타입 => 문자열 타입
    true + ""; // -> "true"
    false + ""; // -> "false"
    

9.3.2 숫자 타입으로 변환

  1. Number 생성자 함수를 new 연산자 없이 호출하는 방법

    1
    2
    3
    4
    5
    6
    7
    
    // 문자열 타입 => 숫자 타입
    Number("0"); // -> 0
    Number("-1"); // -> -1
    Number("10.53"); // -> 10.53
    // 불리언 타입 => 숫자 타입
    Number(true); // -> 1
    Number(false); // -> 0
    
  2. parseInt, parseFloat 함수를 사용하는 방법

    1. 문자열만 가능
    1
    2
    3
    4
    
    // 문자열 타입 => 숫자 타입
    parseInt("0"); // -> 0
    parseInt("-1"); // -> -1
    parseFloat("10.53"); // -> 10.53
    
  3. + 단항 산술 연산자를 이용하는 방법

    1
    2
    3
    4
    5
    6
    7
    
    // 문자열 타입 => 숫자 타입
    +"0"; // -> 0
    +"-1"; // -> -1
    +"10.53"; // -> 10.53
    // 불리언 타입 => 숫자 타입
    +true; // -> 1
    +false; // -> 0
    
  4. * 산술 연산자를 이용하는 방법

    1
    2
    3
    4
    5
    6
    7
    
    // 문자열 타입 => 숫자 타입
    "0" * 1; // -> 0
    "-1" * 1; // -> -1
    "10.53" * 1; // -> 10.53
    // 불리언 타입 => 숫자 타입
    true * 1; // -> 1
    false * 1; // -> 0
    

9.3.3 불리언 타입으로 변환

  1. Boolean 생성자 함수를 new 연산자 없이 호출하는 방법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // 문자열 타입 => 불리언 타입
    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
    
  2. ! 부정 논리 연산자를 두 번 사용하는 방법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // 문자열 타입 => 불리언 타입
    !!"x"; // -> true
    !!""; // -> false
    !!"false"; // -> true
    // 숫자 타입 => 불리언 타입
    !!0; // -> false
    !!1; // -> true
    !!NaN; // -> false
    !!Infinity; // -> true
    // null 타입 => 불리언 타입
    !!null; // -> false
    // undefined 타입 => 불리언 타입
    !!undefined; // -> false
    // 객체 타입 => 불리언 타입
    !!{}; // -> true
    !![]; // -> true
    

9.4 단축 평가

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

  • 표현식을 평가하는 도중 평가 결과가 확정된 경우 나머지 평가 과정 생략

    단축 평가 표현식평가 결과
    true | | anythingtrue
    false | | anythinganything
    true && anythinganything
    false && anythingfalse

논리곱(&&) 연산자와 논리합(||) 연산자

  • 좌항에서 우항으로 평가 진행
  • 논리 연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 그대로 반환
  • 단축 평가 진행
  • 논리곱 연산자는 조건이 Truthy 값일때 수행하는 if문을 대체할 수 있고, 논리곱은 조건이 Falsy 값일때 수행하는 if문을 대체할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    var done = true;
    var message = "";
    
    // 주어진 조건이 true일 때
    if (done) message = "완료";
    
    // if 문은 단축 평가로 대체 가능하다.
    // done이 true라면 message에 '완료'를 할당
    message = done && "완료";
    console.log(message); // 완료
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    var done = false;
    var message = "";
    
    // 주어진 조건이 false일 때
    if (!done) message = "미완료";
    
    // if 문은 단축 평가로 대체 가능하다.
    // done이 false라면 message에 '미완료'를 할당
    message = done || "미완료";
    console.log(message); // 미완료
    

단축 평가의 유용한 패턴

  1. 객체의 프로퍼티 참조시 TypeError를 피할 때

    1. 변수가 객체의 프로퍼티를 가리키려 하지만 사실 null이나 undefined를 가리키고 있다면 에러가 발생한다. 단축평가를 사용하여 이를 피할 수 있다.
    1
    2
    
    var elem = null;
    var value = elem.value; // TypeError: Cannot read property 'value' of null
    
    1
    2
    3
    4
    
    var elem = null;
    // elem이 null이나 undefined와 같은 Falsy 값이면 elem으로 평가되고
    // elem이 Truthy 값이면 elem.value로 평가된다.
    var value = elem && elem.value; // -> null
    
  2. 함수 매개변수에 기본값을 설정할 때

    1. 함수 호출시 인수를 전달하지 않으면 매개변수에 undefined가 할당된다. 단축평가를 이용해 이를 원하는 기본값으로 설정할 수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // 단축 평가를 사용한 매개변수의 기본값 설정
    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
    

9.4.2 옵셔널 체이닝 연산자

1
2
3
4
5
6
var elem = null;

// elem이 null 또는 undefined이면 undefined를 반환하고,
// 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.
var value = elem?.value;
console.log(value); // undefined
  • ES11에서 도입
  • 좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.

객체 프로퍼티 참조시 논리곱 연산자와의 차이

  • 논리곱 연산자는 좌항 피연산자가 Falsy 값이면 좌항 피연산자를 그대로 반환

    1
    2
    3
    4
    5
    6
    7
    
    var str = "";
    
    // 문자열의 길이(length)를 참조한다.
    var length = str && str.length;
    
    // 문자열의 길이(length)를 참조하지 못한다.
    console.log(length); // ''
    
  • 옵셔널 체이닝 연산자는 좌항 피연산자가 null 또는 undefined인 경우만 아니라면 계속 우항의 프로퍼티를 참조

    1
    2
    3
    4
    5
    6
    7
    
    var str = "";
    
    // 문자열의 길이(length)를 참조한다.
    // 이때 좌항 피연산자가 false로 평가되는 Falsy 값이라도
    // null 또는 undefined가 아니면 우항의 프로퍼티 참조를 이어간다.
    var length = str?.length;
    console.log(length); // 0
    

9.4.3 null 병합 연산자

1
2
3
4
// 좌항의 피연산자가 null 또는 undefined이면 우항의 피연산자를 반환하고,
// 그렇지 않으면 좌항의 피연산자를 반환한다.
var foo = null ?? "default string";
console.log(foo); // "default string"
  • ES11에서 도입
  • 좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고 그렇지 않으면 좌항의 피연산자를 반환한다.

변수 기본값 설정시 논리합 연산자와의 차이

  • 논리합 연산자는 좌항 피연산자가 Falsy 값이면 우항 피연산자를 그대로 반환
    1
    2
    3
    
    // Falsy 값인 0이나 ''도 기본값으로서 유효하다면 예기치 않은 동작이 발생할 수 있다.
    var foo = "" || "default string";
    console.log(foo); // "default string"
    
  • null 병합 연산자는 좌항 피연산자가 null 또는 undefined인 경우만 아니라면 좌항 피연산자를 그대로 반환
    1
    2
    3
    4
    
    // 좌항의 피연산자가 Falsy 값이라도
    // null 또는 undefined이 아니면 좌항의 피연산자를 반환한다.
    var foo = "" ?? "default string";
    console.log(foo); // ""
    
This post is licensed under CC BY 4.0 by the author.