본문으로 건너뛰기

"ECMAScript" 태그로 연결된 39개 게시물개의 게시물이 있습니다.

모든 태그 보기

약한 참조와 파이널라이저

· 약 8분
사티야 구나세카란 ([@_gsathya](https://twitter.com/_gsathya)), 마티아스 바이넨스 ([@mathias](https://twitter.com/mathias)), 슈유 꿔 ([@_shu](https://twitter.com/_shu)), 레셰크 스비르스키 ([@leszekswirski](https://twitter.com/leszekswirski))

일반적으로 자바스크립트에서 객체에 대한 참조는 _강하게 유지_됩니다. 즉, 객체를 참조하고 있는 동안에는 가비지 컬렉션이 이루어지지 않습니다.

const ref = { x: 42, y: 51 };
// `ref`(혹은 같은 객체에 대한 다른 참조)를 갖고 있는 한,
// 객체는 가비지 컬렉션되지 않습니다.

현재로서는 WeakMapWeakSet만이 자바스크립트에서 약하게 객체를 참조하는 유일한 방법입니다. WeakMap이나 WeakSet에 객체를 추가해도 가비지 컬렉션을 막을 수는 없습니다.

const wm = new WeakMap();
{
const ref = {};
const metaData = 'foo';
wm.set(ref, metaData);
wm.get(ref);
// → metaData
}
// 이제 이 블록 스코프 내에서 `ref`에 대한 참조를 갖고 있지 않기 때문에,
// `wm`의 키임에도 불구하고 가비지 컬렉션이 가능합니다.

안정적인 `Array.prototype.sort`

· 약 3분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

강아지 배열이 있다고 가정합시다. 각 강아지는 이름과 등급을 가지고 있습니다. (이것이 이상한 예제처럼 느껴진다면, 정확히 이런 내용을 전문으로 하는 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);

Symbol.prototype.description

· 약 1분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

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`

· 약 3분
Mathias Bynens ([@mathias](https://twitter.com/mathias)), JavaScript 전문가

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합니다. 즉, 키 xy는 포함하고, 키 abc는 포함하지 않습니다. 그런 다음 남아있는 entries를 map으로 순회하여 각 키-값 쌍에 대한 업데이트된 쌍을 반환합니다. 이 예제에서는 각 값을 2로 곱하여 두 배로 만듭니다. 최종 결과는 xy 속성만 가지며 새 값이 있는 새 객체입니다.

Promise 조합자들

· 약 4분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

ES2015에서 Promise가 도입된 이후, 자바스크립트는 정확히 두 가지 Promise 조합자: Promise.allPromise.race를 지원했습니다.

현재 두 가지 새로운 제안인 Promise.allSettledPromise.any가 표준화 과정을 진행 중입니다. 이 추가들로 인해 자바스크립트에는 총 네 가지 Promise 조합자가 존재하게 되며, 각각 다른 사용 사례를 가능하게 합니다.

Array.prototype.flat`과 `Array.prototype.flatMap`

· 약 2분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

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]

flatMapmap을 먼저 수행하고 flat을 별도로 수행하는 것보다 조금 더 효율적입니다.

flatMap의 사용 사례에 관심 있으신가요? Axel Rauschmayer의 설명을 확인하세요.

Array#{flat,flatMap} 지원

숫자 구분자

· 약 2분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

큰 숫자 리터럴은 특히 반복되는 숫자가 많을 때, 인간의 눈으로 빠르게 해석하기 어렵습니다:

1000000000000
1019436871.42

가독성을 개선하기 위해 새로운 JavaScript 언어 기능은 숫자 리터럴에서 언더스코어를 구분 기호로 사용할 수 있게 합니다. 따라서 위의 코드는 이제 숫자를 천 단위로 그룹화하여 다시 작성할 수 있습니다:

`String.prototype.matchAll`

· 약 2분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

문자열에서 동일한 정규식을 반복 적용하여 모든 매치를 찾는 것은 일반적인 경우입니다. 어느 정도는 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}`);
}

모듈 네임스페이스 내보내기

· 약 1분
마티아스 비넨스([@mathias](https://twitter.com/mathias))

자바스크립트 모듈에서는 이미 다음 문법을 사용할 수 있었습니다:

import * as utils from './utils.mjs';

그러나 대칭적인 export 문법은 존재하지 않았습니다… 이번엔 다릅니다:

export * as utils from './utils.mjs';

이는 다음과 동등합니다:

import * as utils from './utils.mjs';
export { utils };

공용 및 비공용 클래스 필드

· 약 4분
Mathias Bynens ([@mathias](https://twitter.com/mathias))

여러 제안이 기존 JavaScript 클래스 문법을 새로운 기능으로 확장합니다. 이 글은 V8 v7.2와 Chrome 72에서 새로운 공용 클래스 필드 문법, 그리고 곧 출시될 비공용 클래스 필드 문법에 대해 설명합니다.

IncreasingCounter라는 이름의 클래스 인스턴스를 생성하는 코드 예시는 다음과 같습니다:

const counter = new IncreasingCounter();
counter.value;
// 로그 출력: '현재 값을 가져오는 중!'
// → 0
counter.increment();
counter.value;
// 로그 출력: '현재 값을 가져오는 중!'
// → 1

value 접근 시 코드를 실행한 후 결과를 반환합니다(즉, 메시지가 로그에 출력됩니다). 그렇다면 이 클래스를 JavaScript로 어떻게 구현할 수 있을까요? 🤔

ES2015 클래스 문법

IncreasingCounter를 ES2015 클래스 문법을 사용하여 구현하는 방법은 다음과 같습니다:

class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('현재 값을 가져오는 중!');
return this._count;
}
increment() {
this._count++;
}
}

클래스는 value getter와 increment 메소드를 프로토타입에 설치합니다. 더 흥미로운 것은, 클래스가 생성자인데, 이는 인스턴스 속성 _count를 생성하고 초기값을 0으로 설정합니다. 현재는 언더스코어 접두사를 사용하여 _count를 소비자가 직접 사용하지 않도록 권장합니다. 하지만 이것은 단지 관례일 뿐이며, 언어에 의해 특별한 의미가 부여된 “비공용” 속성은 아닙니다.