최상위 `await`
최상위 await
는 개발자가 비동기 함수 외부에서 await
키워드를 사용할 수 있도록 합니다. 이는 큰 비동기 함수처럼 동작하며, 이를 import
하는 다른 모듈들이 본문의 평가를 시작하기 전에 대기하게 합니다.
최상위 await
는 개발자가 비동기 함수 외부에서 await
키워드를 사용할 수 있도록 합니다. 이는 큰 비동기 함수처럼 동작하며, 이를 import
하는 다른 모듈들이 본문의 평가를 시작하기 전에 대기하게 합니다.
널 병합 제안 (??
)은 기본값을 처리하기 위한 새로운 단축 평가 연산자를 추가합니다.
여러분은 이미 단축 평가 연산자인 &&
와 ||
를 알고 있을 가능성이 높습니다. 이 연산자들은 “true값”과 “false값”을 처리합니다. 예를 들어 lhs && rhs
라는 코드 샘플을 생각해 봅시다. lhs
(좌측 피연산자)가 false값이면, 표현식은 lhs
를 평가합니다. 그렇지 않으면 rhs
(우측 피연산자)를 평가합니다. 반대로 lhs || rhs
라는 코드 샘플의 경우에는, lhs
가 true값이면 표현식은 lhs
를 평가합니다. 그렇지 않으면 rhs
를 평가합니다.
JavaScript에서 긴 속성 접근 체인은 오류를 일으키기 쉽습니다. 이 중 하나라도 null
또는 undefined
(“nullish” 값으로 알려짐)일 수 있기 때문입니다. 각 단계에서 속성 존재 여부를 확인하는 것은 쉽게 깊이 중첩된 if
-문 구조 또는 속성 접근 체인을 복제하는 긴 if
-조건으로 바뀔 수 있습니다:
JSON ⊂ ECMAScript 제안을 통해 JSON은 ECMAScript의 문법적 하위 집합이 되었습니다. 이것이 이미 그렇지 않았다는 사실에 놀란다면, 당신은 혼자가 아닙니다!
ES2018에서는 ECMA스크립트 문자열 리터럴은 U+2028 LINE SEPARATOR와 U+2029 PARAGRAPH SEPARATOR 문자를 탈출하지 않은 상태로 포함할 수 없었습니다. 왜냐하면 그것들이 이 맥락에서도 줄 종결자로 간주되었기 때문입니다:
// U+2028 문자가 포함된 문자열입니다.
const LS = '
';
// → ES2018: SyntaxError
// eval로 생성된 U+2029 문자가 포함된 문자열입니다:
const PS = eval('"\u2029"');
// → ES2018: SyntaxError
이는 JSON 문자열은 이러한 문자를 포함할 수 있기 때문에 문제가 됩니다. 결과적으로, 유효한 JSON을 ECMAScript 프로그램에 포함할 때 개발자는 이러한 문자를 처리하기 위해 특수한 후처리 로직을 구현해야 했습니다. 이러한 로직 없이는 코드에 미묘한 버그가 생기거나 심지어 보안 문제가 발생할 수 있습니다!
현재 Intl.NumberFormat
API에 대해 알고 있을 수도 있습니다. 이 API는 현대 환경에서 이미 오랫동안 지원되고 있습니다.
Intl.NumberFormat
의 기본 형태는 지역별 숫자 형식을 지원하는 재사용 가능한 포매터 인스턴스를 생성할 수 있도록 합니다. 다른 Intl.*Format
API처럼, 포매터 인스턴스는 format
과 formatToParts
메서드 모두를 지원합니다:
웹 브라우저에서 사용하기 위한 JavaScript를 작성한 적이 있다면, 전역 this
에 접근하기 위해 window
를 사용한 적이 있을 것입니다. Node.js에서는 global
을 사용했을지도 모릅니다. 두 환경에서 모두 작동해야 하는 코드를 작성한 경우, 사용할 수 있는 것을 감지하여 이를 사용했을 것입니다. 그러나 지원하려는 환경과 사용 사례가 늘어남에 따라 체크해야 할 식별자의 목록이 증가하면서 금방 복잡해집니다:
일반적으로 자바스크립트에서 객체에 대한 참조는 _강하게 유지_됩니다. 즉, 객체를 참조하고 있는 동안에는 가비지 컬렉션이 이루어지지 않습니다.
const ref = { x: 42, y: 51 };
// `ref`(혹은 같은 객체에 대한 다른 참조)를 갖고 있는 한,
// 객체는 가비지 컬렉션되지 않습니다.
현재로서는 WeakMap
과 WeakSet
만이 자바스크립트에서 약하게 객체를 참조하는 유일한 방법입니다. WeakMap
이나 WeakSet
에 객체를 추가해도 가비지 컬렉션을 막을 수는 없습니다.
const wm = new WeakMap();
{
const ref = {};
const metaData = 'foo';
wm.set(ref, metaData);
wm.get(ref);
// → metaData
}
// 이제 이 블록 스코프 내에서 `ref`에 대한 참조를 갖고 있지 않기 때문에,
// `wm`의 키임에도 불구하고 가비지 컬렉션이 가능합니다.
강아지 배열이 있다고 가정합시다. 각 강아지는 이름과 등급을 가지고 있습니다. (이것이 이상한 예제처럼 느껴진다면, 정확히 이런 내용을 전문으로 하는 Twitter 계정이 있다는 것을 알아두세요... 묻지 마세요!)
// 배열이 `name` 기준으로 알파벳 순서로 미리 정렬되어 있는 것을 확인하세요.
const doggos = [
{ name: 'Abby', rating: 12 },
{ name: 'Bandit', rating: 13 },
{ name: 'Choco', rating: 14 },
{ name: 'Daisy', rating: 12 },
{ name: 'Elmo', rating: 12 },
{ name: 'Falco', rating: 13 },
{ name: 'Ghost', rating: 14 },
];
// 강아지를 내림차순으로 `rating` 기준으로 정렬합니다.
// (이 작업은 `doggos`를 제자리에서 업데이트합니다.)
doggos.sort((a, b) => b.rating - a.rating);
JavaScript Symbol
은 생성 시 설명을 제공할 수 있습니다:
const symbol = Symbol('foo');
// ^^^^^
이전에는 이를 프로그래밍적으로 접근하는 유일한 방법은 Symbol.prototype.toString()
을 간접적으로 사용하는 것이었습니다:
const symbol = Symbol('foo');
// ^^^^^
symbol.toString();
// → 'Symbol(foo)'
// ^^^
symbol.toString().slice(7, -1); // 🤔
// → 'foo'
하지만 위 코드의 형태는 약간 마법 같아 보이고, 매우 직관적이지 않으며 “의도를 표현하되, 구현을 표현하지 않는다”라는 원칙을 위반합니다. 위 기법은 또한 설명이 없는 Symbol(Symbol()
)과 빈 문자열을 설명으로 가진 Symbol(Symbol('')
)을 구분할 수 없게 합니다.
Object.fromEntries
는 자바스크립트 내장 라이브러리에 유용한 추가 기능입니다. 무엇을 하는지 설명하기 전에 기존의 Object.entries
API를 이해하는 것이 도움이 됩니다.
Object.entries
Object.entries
API는 이미 오래전부터 존재해 왔습니다.
객체의 각 키-값 쌍에 대해 Object.entries
는 첫 번째 요소가 키이고 두 번째 요소가 값인 배열을 제공합니다.
Object.entries
는 특히 for
-of
와 결합할 때 유용하며, 객체의 모든 키-값 쌍을 우아하게 순회할 수 있게 합니다:
const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]
for (const [key, value] of entries) {
console.log(`The value of ${key} is ${value}.`);
}
// 출력:
// The value of x is 42.
// The value of y is 50.
불행히도, 현재까지는 entries 결과를 동일한 객체로 되돌리는 간단한 방법이 없었습니다… 이제는 가능합니다!
Object.fromEntries
새로운 Object.fromEntries
API는 Object.entries
의 반대 동작을 수행합니다. 이를 통해 entries를 기반으로 객체를 손쉽게 다시 구성할 수 있습니다:
const object = { x: 42, y: 50 };
const entries = Object.entries(object);
// → [['x', 42], ['y', 50]]
const result = Object.fromEntries(entries);
// → { x: 42, y: 50 }
일반적인 사용 사례 중 하나는 객체를 변환하는 것입니다. 이제 entries를 순회하고 이미 익숙한 배열 메서드를 사용하여 수행할 수 있습니다:
const object = { x: 42, y: 50, abc: 9001 };
const result = Object.fromEntries(
Object.entries(object)
.filter(([ key, value ]) => key.length === 1)
.map(([ key, value ]) => [ key, value * 2 ])
);
// → { x: 84, y: 100 }
이 예제에서는 길이가 1
인 키만 가져오도록 객체를 filter
합니다. 즉, 키 x
와 y
는 포함하고, 키 abc
는 포함하지 않습니다. 그런 다음 남아있는 entries를 map
으로 순회하여 각 키-값 쌍에 대한 업데이트된 쌍을 반환합니다. 이 예제에서는 각 값을 2
로 곱하여 두 배로 만듭니다. 최종 결과는 x
와 y
속성만 가지며 새 값이 있는 새 객체입니다.