Promise 조합자들
ES2015에서 Promise가 도입된 이후, 자바스크립트는 정확히 두 가지 Promise 조합자: Promise.all
과 Promise.race
를 지원했습니다.
현재 두 가지 새로운 제안인 Promise.allSettled
와 Promise.any
가 표준화 과정을 진행 중입니다. 이 추가들로 인해 자바스크립트에는 총 네 가지 Promise 조합자가 존재하게 되며, 각각 다른 사용 사례를 가능하게 합니다.
ES2015에서 Promise가 도입된 이후, 자바스크립트는 정확히 두 가지 Promise 조합자: Promise.all
과 Promise.race
를 지원했습니다.
현재 두 가지 새로운 제안인 Promise.allSettled
와 Promise.any
가 표준화 과정을 진행 중입니다. 이 추가들로 인해 자바스크립트에는 총 네 가지 Promise 조합자가 존재하게 되며, 각각 다른 사용 사례를 가능하게 합니다.
Array.prototype.flat
이 예제의 배열은 여러 수준으로 중첩되어 있습니다. 배열 안에 또 다른 배열이 포함됩니다.
const array = [1, [2, [3]]];
// ^^^^^^^^^^^^^ 외부 배열
// ^^^^^^^^ 내부 배열
// ^^^ 가장 안쪽 배열
Array#flat
은 주어진 배열의 평탄화된 버전을 반환합니다.
array.flat();
// → [1, 2, [3]]
// …다음과 동등합니다:
array.flat(1);
// → [1, 2, [3]]
기본 깊이는 1
이지만, 원하는 깊이까지 재귀적으로 평탄화를 실행하려면 숫자를 전달할 수 있습니다. 배열에 더 이상 중첩 배열이 없을 때까지 평탄화를 계속하려면 Infinity
를 전달합니다.
// 배열에 더 이상 중첩된 배열이 포함되지 않을 때까지 재귀적으로 평탄화:
array.flat(Infinity);
// → [1, 2, 3]
왜 이 메서드를 Array.prototype.flatten
이 아니라 Array.prototype.flat
으로 명명했는지 궁금하신가요? #SmooshGate에 대한 우리의 설명을 읽어보세요!
Array.prototype.flatMap
다음은 또 다른 예제입니다. 값 하나를 두 번 포함하는 배열을 반환하는 duplicate
함수를 정의합니다. 이 배열의 각 값에 duplicate
를 적용하면 중첩된 배열이 생성됩니다.
const duplicate = (x) => [x, x];
[2, 3, 4].map(duplicate);
// → [[2, 2], [3, 3], [4, 4]]
그런 다음 결과에 flat
을 호출하여 배열을 평탄화할 수 있습니다:
[2, 3, 4].map(duplicate).flat(); // 🐌
// → [2, 2, 3, 3, 4, 4]
이 패턴이 함수형 프로그래밍에서 매우 일반적이기 때문에, 이를 위한 전용 flatMap
메서드가 새로 추가되었습니다.
[2, 3, 4].flatMap(duplicate); // 🚀
// → [2, 2, 3, 3, 4, 4]
flatMap
은 map
을 먼저 수행하고 flat
을 별도로 수행하는 것보다 조금 더 효율적입니다.
flatMap
의 사용 사례에 관심 있으신가요? Axel Rauschmayer의 설명을 확인하세요.
Array#{flat,flatMap}
지원큰 숫자 리터럴은 특히 반복되는 숫자가 많을 때, 인간의 눈으로 빠르게 해석하기 어렵습니다:
1000000000000
1019436871.42
가독성을 개선하기 위해 새로운 JavaScript 언어 기능은 숫자 리터럴에서 언더스코어를 구분 기호로 사용할 수 있게 합니다. 따라서 위의 코드는 이제 숫자를 천 단위로 그룹화하여 다시 작성할 수 있습니다:
문자열에서 동일한 정규식을 반복 적용하여 모든 매치를 찾는 것은 일반적인 경우입니다. 어느 정도는 String#match
메서드를 사용하여 오늘날에도 가능합니다.
이 예제에서, 우리는 16진수 숫자로만 구성된 모든 단어를 찾고 각 매치를 로그로 출력합니다:
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.match(regex)) {
console.log(match);
}
// 출력:
//
// 'DEADBEEF'
// 'CAFE'
그러나 이것은 매치된 _서브스트링_만 제공합니다. 일반적으로 여러분은 서브스트링뿐만 아니라 각 서브스트링의 인덱스 또는 각 매치 내의 캡처 그룹과 같은 추가 정보를 원합니다.
자체 반복문을 작성하고 매치 객체를 스스로 추적함으로써 이를 달성할 수 있습니다. 그러나 이것은 다소 번거롭고 그렇게 편리하지 않습니다:
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
let match;
while (match = regex.exec(string)) {
console.log(match);
}
// 출력:
//
// [ 'DEADBEEF', index: 19, input: 'Magic hex numbers: DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: 'Magic hex numbers: DEADBEEF CAFE' ]
새로운 String#matchAll
API를 사용하면 이전보다 더 쉽게 매치 객체를 얻을 수 있습니다. 이제 간단한 for
-of
루프를 작성하여 모든 매치 객체를 가져올 수 있습니다.
const string = 'Magic hex numbers: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.matchAll(regex)) {
console.log(match);
}
// 출력:
//
// [ 'DEADBEEF', index: 19, input: 'Magic hex numbers: DEADBEEF CAFE' ]
// [ 'CAFE', index: 28, input: 'Magic hex numbers: DEADBEEF CAFE' ]
String#matchAll
은 캡처 그룹이 포함된 정규식에서 특히 유용합니다. 이는 각 개별 매치에 대한 캡처 그룹 포함 정보를 제공합니다.
const string = 'Favorite GitHub repos: tc39/ecma262 v8/v8.dev';
const regex = /\b(?<owner>[a-z0-9]+)\/(?<repo>[a-z0-9\.]+)\b/g;
for (const match of string.matchAll(regex)) {
console.log(`${match[0]} at ${match.index} with '${match.input}'`);
console.log(`→ owner: ${match.groups.owner}`);
console.log(`→ repo: ${match.groups.repo}`);
}
모던 웹 애플리케이션은 종종 동적 데이터로 구성된 목록을 사용합니다. 예를 들어, 사진 뷰어 앱은 다음과 같은 내용을 표시할 수 있습니다:
이 사진에는 Ada, Edith, 그리고 Grace가 포함되어 있습니다.
텍스트 기반 게임은 다른 종류의 목록을 가질 수 있습니다:
초능력을 선택하세요: 투명화, 염력, 또는 공감 능력.
각 언어에는 다른 목록 포맷팅 규칙과 단어가 있기 때문에 로컬화된 목록 포맷터를 구현하는 것은 간단하지 않습니다. 지원하고자 하는 각 언어에 대해 모든 단어(위 예에서는 '그리고' 또는 '혹은'과 같은 단어)를 목록화해야 할 뿐만 아니라, 이러한 언어들의 정확한 포맷팅 규칙을 인코딩해야 합니다! Unicode CLDR은 이러한 데이터를 제공하지만 이를 JavaScript에서 사용하려면 다른 라이브러리 코드와 함께 임베드되어 제공되어야 합니다. 이는 불행히도 이러한 라이브러리의 번들 크기를 증가시켜 로드 시간, 파싱/컴파일 비용, 메모리 소비에 부정적인 영향을 미칩니다.
여러 제안이 기존 JavaScript 클래스 문법을 새로운 기능으로 확장합니다. 이 글은 V8 v7.2와 Chrome 72에서 새로운 공용 클래스 필드 문법, 그리고 곧 출시될 비공용 클래스 필드 문법에 대해 설명합니다.
IncreasingCounter
라는 이름의 클래스 인스턴스를 생성하는 코드 예시는 다음과 같습니다:
const counter = new IncreasingCounter();
counter.value;
// 로그 출력: '현재 값을 가져오는 중!'
// → 0
counter.increment();
counter.value;
// 로그 출력: '현재 값을 가져오는 중!'
// → 1
value
접근 시 코드를 실행한 후 결과를 반환합니다(즉, 메시지가 로그에 출력됩니다). 그렇다면 이 클래스를 JavaScript로 어떻게 구현할 수 있을까요? 🤔
IncreasingCounter
를 ES2015 클래스 문법을 사용하여 구현하는 방법은 다음과 같습니다:
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('현재 값을 가져오는 중!');
return this._count;
}
increment() {
this._count++;
}
}
클래스는 value
getter와 increment
메소드를 프로토타입에 설치합니다. 더 흥미로운 것은, 클래스가 생성자인데, 이는 인스턴스 속성 _count
를 생성하고 초기값을 0
으로 설정합니다. 현재는 언더스코어 접두사를 사용하여 _count
를 소비자가 직접 사용하지 않도록 권장합니다. 하지만 이것은 단지 관례일 뿐이며, 언어에 의해 특별한 의미가 부여된 “비공용” 속성은 아닙니다.
JSON.stringify
는 이전에 입력에 고립된 서러게이트가 포함되어 있으면 잘못된 유니코드 문자열을 반환하도록 지정되었습니다:
JSON.stringify('\uD800');
// → '"�"'
“잘 구성된 JSON.stringify
” 제안은 JSON.stringify
의 동작을 변경하여 고립된 서러게이트에 대해 이스케이프 시퀀스를 출력하도록 하고, 결과가 유효한 유니코드(및 UTF-8로 표현 가능)가 되도록 만듭니다:
자바스크립트 모듈은 이제 모든 주요 브라우저에서 지원됩니다!
이 글은 JS 모듈을 사용하는 방법, 이를 책임감 있게 배포하는 방법, 그리고 크롬 팀이 미래에 모듈을 더 나은 방향으로 개선하기 위해 노력하고 있는 방식을 설명합니다.
JS 모듈(“ES 모듈” 또는 “ECMAScript 모듈”이라고도 함)은 주요 새로운 기능 또는 새로운 기능들의 모음입니다. 과거에 사용자 정의 자바스크립트 모듈 시스템을 사용한 적이 있을 것입니다. 아마도 Node.js에서 사용하는 CommonJS를 사용했거나, AMD를 사용했을 수 있습니다. 아니면 다른 것을 사용했을 수도 있습니다. 이러한 모든 모듈 시스템의 공통점은 무엇인가를 가져오고 내보내는 기능을 제공한다는 점입니다.