ES2018 ~ 2020 정리

주형(Jureamer)·2022년 11월 17일
0

ECMA

목록 보기
2/3
post-custom-banner

ES2016 ~ 2017 정리에 이어서 2018 ~ 2020까지도 정리해보려고 한다.
Dev.white님의 글이 잘 정리되어있어 참고하여 작성했다.

ES2018

Rest / Spread Properties

기존에 배열에서 사용하던 rest/spread를 객체에서도 사용 가능하게 되었다.
배열에 있는 것은 적극적으로 썼지만 객체에서는 낯설게 느껴져 잘 쓰지 않았는데
이번 기회에 손에 익혀야겠다고 다시 다짐을!

// Rest 예시
const {open, close, ...etc} = {open: 6, close: 21, name: "ssada", position: "busan"};
console.log(open, close, etc); // 6, 21, {name: "ssada", position: "busan"

// Spread 예시
const otherShop = { open, close, ...etc };
console.log(otherShop); // {open: 6, close: 21, name: "ssada", position: "busan"};

// 복사 예시
const otherShop2 = {open: 9}
const otherShop3 = {open, close, ...etc, ...otherShop2};
console.log(oterhShop3) // {open: 9, close: 21, name: "ssada", position: "busan"};
  • 복사 시 속성이 중복될 경우 가장 마지막에 들어온 속성으로 덮어씌워진다!

Promise.finally()

Promise 사용 시 then, catch 말고도 종료 시 사용가능한 finally가 이때 추가 되었다.
실 사용 시에도 쓰고 있던 기능이었는데 ES2018에 나왔었구나//!

Promise.resolve(data)
.then((res) => console.log(res))
.catch((err) => console.log(err))
.finally(() => console.log("promise 종료"))

Asynchronous iteration

비동기 이터러블 객체를 순회할 수 있게 되었다.
아직 실무에선 써본적은 없지만 반복 가능한 비동기 이터러블 객체를 돌면서
작업을 할 수 있는 특성이 Promise.all과 흡사한 것 같아서 찾아보았다.
그랬더니 해당 글을 통해 명쾌한 답을 얻을 수 있었다. Promise.all은 병렬적으로 진행되고 for await of은 순차적으로 진행되기에 필요에 따라 골라서 쓰면 되는 것이다!! 예쓰!

ES2019

String.trimStart() & trimEnd()

문자열의 앞이나 뒤의 공백을 제거하는 메소드다.

const noun = "    apple"
const adjective = "is delicious     "

console.log(noun.trimStart() + " " + adjective.trimEnd());
// => "apple is delicious"

Optional Catch Binding

catch에 매개변수를 주지 않아도 catch 블록을 사용할 수 있다.
오류 정보와 관계없이 핸들링 해도 될 때 사용하면 좋겠다는 생각이 든다.
하지만 아직 나는 매개변수 없인 못살아..ㅠ

// 기존
try {
  // some code
} catch (err) or catch () {
  // error handling code
}

// 변경
try {
  // some code
} catch {
  // error haddling code
}

Object.fromEntries()

Object.entries()의 정반대로 entries 형태의 배열을 다시 객체로 만들 수 있다.

const studentObj = { name: "jihoon", age: 18};
const entries = Object.entries(studentObj);
console.log(entries); // [['name', 'jihoon'],['age',18]]

const fromEntries = Object.fromEntries(entries);
console.log(fromEntries); // { name: "jihoon", age: 18};

Array.flat() & flatMap()

flat 메소드는 배열 안의 배열을 flat(평탄화)하게 만든다.
flatMap은 map을 flat한 배열로 만든다.

// flat 예시
const arr1 = [1, 2, [3, 4, [5, 6]]];
arr1.flat();
// [1, 2, 3, 4, [5, 6]]

const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(2);
// [1, 2, 3, 4, 5, 6]

const arr3 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr3.flat(Infinity);

// flatMap 예시
let arr1 = [1, 2, 3, 4];

arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]

arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]

써본 적은 없는데 예시를 보니 아주 심플하고 유용할 것 같다!
하지만 flat()은 V8엔진에서 최적화 되지 않았기 때문에 배열이 아주~ 길다면 concat과 reduce를 사용하여
평탄화하는 편이 훨씬 빠르다고 한다. (참고)

또 flatMap은 한 레벨만 평탄화가 가능하다!

ES2020

Dynamic Import

export / import로 모듈을 불러오는 일반적인 방식을 static import(정적 불러오기)라고 칭한다.
정적 불러오기는 문서의 가장 상위에 위치해야하고 블록문 안에 위치할 수 없는 등의 제약 사항이 있다.
동적 불러오기는 import() 구문으로 사용할 수 있는데 프로미스 객체를 반환한다. 함수를 호출하는 문법을 취하고 있으나, import는 함수가 아니다. 이를 통해 모듈들을 사용자가 원할 때만(동적으로) 불러오게끔 할 수 있다.
동적 불러오기를 통해 정적 import를 통해 로딩이 느려지는 것을 방지하여 불필요한 리소스를 줄일 수 있을 것으로 예상된다~!

// 정적 불러오기

import multiple from './multiple.js';
console.log(multiple(10, 5)); // 50


// 동적 불러오기
if (isNormal) {
	import('./multiple.js')
  	.then(multiple => console.log(multiple(10, 5))) // 50
}

BigInt

BigInt2^53보다 큰 정수를 취급하기 위해 등장했다. Bigint는 원시타입으로, 숫자 마지막에 n을 붙이면 BigInt 형태가 된다. BigInt와 Number 타입은 계산할 수 없으며, BigInt끼리 계산만 가능하다.

const bigIntNumber = BigInt(9007199254740991)
// 9007199254740991n

const bigIntString = BigInt("9007199254740991")
// 9007199254740991n

console.log(typeof 1n === 'bigint') // true
console.log(typeof 2n + 3n === 'bigint') // true
console.log(2n + 3) // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

Promise.allSettled

Promise.allSettled()은 모든 작업이 성공(resolve)해야 실행되는 Promise.all과 달리 도중에 실패(reject) 되더라도 모든 실행을 할 수 있다. 순차적으로 할 필요가 없을 때(병렬적), 그리고 모든 작업이 성공적이지 않아도 될 때는 Promise.allSettled()를 써보도록 하자! 순차적인 작업에선 for-wait-of을 택하는 편이 낫다!

function filterUnderNumberFive(num) {
    return new Promise((resolve, reject) => {
        if (num >= 5) {
            resolve(true);
        } else {
            reject(`error by ${num}`)
        }
    });
}

async function executePromises() {
    let arr = [11, 6, 15, 24, 9, 4, 7, 8, 9, 10];
    
    const promises = arr.map((num) => filterUnderNumberFive(num))
    const result = [];
    try {
        const promiseResult = await Promise.all(promises)
        result.push(...promiseResult);
        console.log(result)
    } catch (e) {
        console.log(`error: ${e}`)
    }
}

executePromises();

/* 
promiseAll 결과
error: error by 4
*/

/*
promiseAllSettled 결과
[
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true },
  { status: 'rejected', reason: 'error by 4' },
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true },
  { status: 'fulfilled', value: true }
]
*/

Nullish Coalescing Operator

a ?? b 형태로 사용할 수 있는데, 앞의 값이 null이나 undefined일 때만 b를 반환한다.
즉, x = (a !== null && a !== undefined) ? a : b;와 같다.

let firstName = null;
let lastName = null;
let nickName = "바이올렛";

// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? "익명"); // 바이올렛
      
nickname = undefined;
      
alert(firstName ?? lastName ?? nickName ?? "익명"); // 익명

||과 비슷하지만 0을 다룰 때는 주의해야한다. ??에서는 0이 truthy한 값으로 취급되기 때문이다.

let height = 0
alert(height || 100); // 100
alert(height ?? 100); // 0

Optional Chaining

Object 속성 값을 지정할 때 해당 속성이 없으면 error가 나게 된다. 이를 방지하기 위해 ?을 추가한다면 값이 없을 때 undefined를 return해주어 좀 더 안정성을 보장할 수 있게 된다.

옵셔널 체이닝 문법 ?.은 세가지 형태로 사용할 수 있다.

  • obj?.prop – obj가 존재하면 obj.prop을 반환하고, 그렇지 않으면 undefined를 반환함
  • obj?.[prop] – obj가 존재하면 obj[prop]을 반환하고, 그렇지 않으면 undefined를 반환함
  • obj?.method() – obj가 존재하면 obj.method()를 호출하고, 그렇지 않으면 undefined를 반환함

But, ?.은 읽기나 삭제하기에는 사용할 수 있지만 쓰기에는 사용할 수 없다.

// ?의 세가지 형태
const obj = {
    name: "Jihoon",
    age: 28,
    getPhoneNumber() {
        return "don't have a phone"
    }
}

obj?.name = "Violet"; // SyntaxError: Invalid left-hand side in assignment
// 에러가 발생하는 이유는 undefined = "Violet"이 되기 때문

console.log(obj?.name) // "Jihoon"
console.log(obj?.age) // 28
console.log(obj?.getPhoneNumber()) // "don't have a phone"
console.log(obj?.abc.age) // Cannot read properties of undefined (reading 'age')
console.log(obj?.abc?.age) // undefined

참고

profile
작게라도 꾸준히 성장하는게 목표입니다.
post-custom-banner

0개의 댓글