ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 새롭게 도입된 ES2021 문법
    JavaScript 2021. 1. 1. 20:44

    새롭게 도입되었다기보다는 현재 Stage 4에 올라간 4가지 문법들을 소개해보고자 한다.

    꽤나 흥미로운 문법들이 많다.

    기존 문법으로 사용했을 때보다 코드량이 줄어들 수 있게 해준다거나

    새로운 기능이 등장했다거나

    기존 문법의 불편함을 해소해줄만한 문법들이 등장하였다.

     

    1. String.prototype.replaceAll

     

    기존에 있었던 replace에서 모든 문자열을 바꿔주려면 다음과 같이 적용했어야 했다.

    또한 replace는 global flag를 붙여주지 않으면 첫번째로 찾은 녀석만 바꿔주었다.

    const str = 'abcabcabc'
    
    console.log(str.replace(/a/g, '*'))
    // *bc*bc*bc

    그러나 ES2021에 등장한 replaceAll은 정규표현식이 필요없이 자동으로 global flag가 적용이 된다.

     

    const str = 'abcabcabc'
    
    console.log(str.replaceAll('a', '*'))
    // *bc*bc*bc

    정규표현식으로도 검색이 가능하다.

    다만 replaceAll에서는 에러가 발생하는 경우가 있는데 무엇인고 알아보니

    global flag를 붙여주지 않으면 Type Error가 발생한다.

    TypeError

    2. Promise.any()

    @ settled는 Promise의 상태 (pending, fulfilled, rejected) 중에서 fulfilled 또는 rejected 상태를 settled 상태라고 한다.

     

    먼저 기존에 있던 메서드들의 기능은 이렇다

    Promise.allSettled()
    /*
    => 모든 Promise의 결과(fulfilled, rejected)가 나올 때까지 기다리고 결과값을 담은 iterable 객체를 반환
    => 반환값 형태는 [{status: 'fulfilled', value: 1}, {status: 'rejected', reason: '?'}]
    */               
    
    Promise.all() 
    /*
    => iterable을 인수로 받고 배열이라면 배열 내부의 프로미스 중에서 처리되는데
    가장 오래걸리는 프로미스의 시간+(아주 조금의 시간)이 이 메서드가 종료되는데 걸리는 시간이다.
    인수로 전달받은 프로미스 중에서 하나라도 rejected 상태가 되면
    나머지 프로미스들은 fulfilled 상태를 기다리지 않고 즉시 종료한다
    */                 
    Promise.race() 
    /*
    => 가장 먼저 fulfilled처리되는 Promise의 결과를 반환하고,
    all 메서드와 동일하게 하나라도 rejected 되면 reject하는 새로운 프로미스를 반환
    */

     

    타입은 이렇게 생겼다.

    Promise.any<T>(promises: Iterable<Promise<T>>): Promise<T>

    <T>라는 것은 TypeScript의 Generic 문법인데 해당 문법을 모르는 사람은

    TypeScript 공식홈페이지에서 Generic 문법을 공부해보는 것을 추천한다.

     

    Promise.any()는 가장 첫번째로 fulfilled가 되는 것을 반환한다.

    Promise.any([
      new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러2')), 1000)),
      new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러1')), 2000)),
      new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러3')), 3000))
    ]).then(alert);
    
    // 3개의 Promise가 모두 reject가 되면 알림으로 Error가 떠야할텐데 뜨지 않으면서
    // Uncaught (in promise) AggregateError: All promises were rejected라는 에러가 발생한다.
    
    Promise.any([
      new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러2')), 1000)),
      new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러1')), 2000)),
      new Promise((resolve, reject) => setTimeout(() => resolve(new Error('에러3')), 3000))
    ]).then(alert);
    
    // 하나라도 resolve가 되면 resolve된 값을 반환함
    
    => 솔직히 영어문서보고 단어의 뜻이 다 비슷비슷해서 무슨 말인지 잘 몰라서
        크롬 브라우저 콘솔창에 쳐보니 이러한 결론이 나왔다.
        
    결론: Promise.any()는 여러 Promise들 중에서 모두 rejected이면 에러가 발생하고
    단 하나라도 fulfilled가 되면 그 값을 반환하고 any의 상태는 fulfilled가 된다

     

     

    3. Logical assignment operators (논리 할당 연산자)

    이 문법은 아직 codeSandbox에서 지원하지 않으니 주의

    // 좌변 => 우변은 둘이 같다는 뜻이다.
    a ||= b => a || (a = b)
    a &&= b => a && (a = b)
    a ??= b => a ?? (a = b)

    아직 &&, ||, ??을 모르는 사람이 있을 수 있으니 먼저 설명하고 간다.

    a || b
    => a ? a : b
    => a가 true이면 a, 그렇지 않으면 b
    
    a && b
    => !a ? a : b
    => a가 true이면 b, 그렇지 않으면 a
    
    a ?? b
    => a !== null && a !== undefined ? a : b
    =>  a가 null도 아니고 undefined도 아니면 a, a가 null 또는 undefined이면 b
    
    // a가 null, b가 undefined이면 a ?? b는 null이고
    // a가 undefined, b가 null이면 a ?? b는 undefined이다

     

    논리 할당 연산의 값 도출 과정

    // 말이 안되긴 하지만 설명을 위해 억지가 있을 수 있음
    
    let a = false
    let b = true
    
    a ||= b
    => a || (a=b)
    => false || (false = true)
    => false || true
    => false
    
    a &&= b
    => a && (a = b)
    => false && (false = true)
    => false && true
    => false
    
    let a = true
    let b = false
    
    a ||= b
    => a || (a = b)
    => true || (true = false)
    => true || false
    => true
    
    a &&= b
    => a && (a = b)
    => true && (true = false)
    => true && false
    => false
    
    let a = null
    let b = 1
    
    a ??= b
    => a ?? (a = b)
    => null ?? (null = 1)
    => null ?? 1
    => null
    

     

    4. Numeric separators (숫자 구분자)

    우리는 숫자를 이때껏 이렇게 사용했었다.

    const number1 = 1e9
    const number2 = 10000
    const number3 = 3.44

    1e9의 경우에는 1*10**9이라는 뜻이다. (10의 9제곱)

     

    어떤 때에는 숫자가 길어서 단위를 끊고 싶었을 것이다.

    이런 불편함을 해소 해주는 것이 Numeric separator이다.

     

    무엇인지 알아보자

    숫자 사이에 _를 삽입함으로서 가독성이 올라간다.

    _는 단지 가독성을 올려주는 역할이지 실제로는 _없이 작동한다.

    let num1 = 1_2
    let num2 = 1_4
    // 숫자 사이에 _ (언더바) 삽입
    
    const phoneNumber = 110_1234_1234

    연산도 가능하다.

    let num1 = 1_2
    let num2 = 1_4
    
    // 덧셈
    console.log(num1 + num2) // 26
    
    // 나눗셈
    console.log(num1 - num2) // -2
    
    // 곱셈
    console.log(num1 * num2) // 168
    
    // 나눗셈
    console.log(num1 / num2) // 0.8571428571428571
    
    // 나머지 연산
    console.log(num1 % num2) // 12
    
    // 거듭제곱
    console.log(num1 ** num2) // 1283918464548864
    
    // 제곱근
    console.log(Math.sqrt(num1)) // 3.4641016151377544

    심지어 지수법표기, 10진법 이외의 것도 가능하다.

    console.log(1e2_1) // 1e+21
    
    let num = 0b1011 // 0b 다음 숫자는 2진수이다. 2진수 1011 === 10진수 11
    console.log(num + 0b1) // 12
    // 2진법, 8진법, 16진법 모두 가능하다

     

    다만 숫자 구분에도 제약 사항이 있다.

    1. 표기법

    구분 연산자 _는 반드시 숫자와 숫자 사이에 위치해야 하며
    표기법을 지키지 않으면 문법 에러가 발생한다
    Uncaught SyntaxError: Invalid or unexpected token
    
    숫자 7을 2진법으로 표기할 때
    0b111 (O)
    0b11_1 (O) 
    0_b111 (X)
    0b_111 (X)
    
    소수를 표기할 때
    3.141 (O)
    3.1_41 (O)
    3._141 (X)
    3_.141 (X)
    
    1보다 큰 Big Integer를 표기할 때
    1e21 (O)
    1e2_1 (O)
    1_e21 (X)
    1e_21 (X)
    
    1보다 작은 수를 표기할 때
    1e-21 (O)
    1e-2_1 (O)
    1e-_21 (X)
    1e_-21 (X)
    
    단순 숫자를 표기할 때
    100002223 (O)
    1_0000_2223 (O)
    _100002223 (X)
    100002223_ (X)
    

    2. 메소드 미지원

    미지원하는 이유에 대한 설명: 링크

    parseInt, parseFloat, Number를 미지원한다
    미지원하는 이유를 알아보니 아래와 같이 설명되어 있다
    '숫자 구분자가 코드용이고, 다른 종류의 입력은 다르게 처리되어야 한다'
    
    parseInt('345_345') // 345
    Number('345_345') // NaN

    3. 메소드 미지원에 대한 해결책

    해결책은 다음과 같이 제시되어있다.

    replace나 replaceAll을 이용하여 구분자를 빼면 된다.

    function removeUnderbars(str) {
        str = str.replace(/[^0-9]/gu, '');
        return Number(str);
    }
    
    console.log(removeUnderbars('123_123_123')) // 123123123

     

    다소 복잡한 것도 있었지만 대부분 원래 있던 것들에서 변형된 것들 같다.

    그 중 Promise번역이 조금 어려웠지만 Promise에 대해서 복습한 기회가 된 것 같다.

    ES2021 문법에 좋은 기능이 많은 것 같다.

    Tistory 코드 블럭에 타입스크립트도 지원해줬으면 좋겠다...

    댓글

Designed by Tistory.