ES2016 ~ 2017 정리에 이어서 2018 ~ 2020까지도 정리해보려고 한다.
Dev.white님의 글이 잘 정리되어있어 참고하여 작성했다.
기존에 배열에서 사용하던 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 사용 시 then, catch 말고도 종료 시 사용가능한 finally가 이때 추가 되었다.
실 사용 시에도 쓰고 있던 기능이었는데 ES2018에 나왔었구나//!
Promise.resolve(data)
.then((res) => console.log(res))
.catch((err) => console.log(err))
.finally(() => console.log("promise 종료"))
비동기 이터러블 객체를 순회할 수 있게 되었다.
아직 실무에선 써본적은 없지만 반복 가능한 비동기 이터러블 객체를 돌면서
작업을 할 수 있는 특성이 Promise.all
과 흡사한 것 같아서 찾아보았다.
그랬더니 해당 글을 통해 명쾌한 답을 얻을 수 있었다. Promise.all은 병렬적으로 진행되고 for await of은 순차적으로 진행되기에 필요에 따라 골라서 쓰면 되는 것이다!! 예쓰!
문자열의 앞이나 뒤의 공백을 제거하는 메소드다.
const noun = " apple"
const adjective = "is delicious "
console.log(noun.trimStart() + " " + adjective.trimEnd());
// => "apple is delicious"
catch에 매개변수를 주지 않아도 catch 블록을 사용할 수 있다.
오류 정보와 관계없이 핸들링 해도 될 때 사용하면 좋겠다는 생각이 든다.
하지만 아직 나는 매개변수 없인 못살아..ㅠ
// 기존
try {
// some code
} catch (err) or catch () {
// error handling code
}
// 변경
try {
// some code
} catch {
// error haddling code
}
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};
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은 한 레벨만 평탄화가 가능하다!
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
는 2^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()
은 모든 작업이 성공(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 }
]
*/
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
Object 속성 값을 지정할 때 해당 속성이 없으면 error가 나게 된다. 이를 방지하기 위해 ?
을 추가한다면 값이 없을 때 undefined
를 return해주어 좀 더 안정성을 보장할 수 있게 된다.
옵셔널 체이닝 문법 ?.
은 세가지 형태로 사용할 수 있다.
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