Статьи

Что нового в ES2018

В этой статье я расскажу о новых функциях JavaScript, представленных в ES2018 (ES9), с примерами того, для чего они предназначены и как их использовать.

JavaScript (ECMAScript) — это постоянно развивающийся стандарт, реализуемый многими поставщиками на разных платформах. ES6 (ECMAScript 2015) был крупным выпуском, для завершения которого потребовалось шесть лет. Новый ежегодный процесс выпуска был разработан, чтобы упростить процесс и быстрее добавлять функции. ES9 (ES2018) — самая последняя итерация на момент написания.

Технический комитет 39 (TC39) состоит из сторон, включая поставщиков браузеров, которые встречаются, чтобы продвигать предложения JavaScript по строгому пути развития:

Этап 0: соломенный
Первоначальная подача идей.

Этап 1: предложение —
Официальный документ предложения, отстаиваемый по крайней мере один раз членом TC39, который включает примеры API.

Этап 2: черновик —
Начальная версия спецификации функции с двумя экспериментальными реализациями.

Этап 3: кандидат —
Спецификация предложения пересматривается, и отзывы собираются от поставщиков.

Этап 4: закончен —
Предложение готово для включения в ECMAScript, но его доставка может занять больше времени в браузерах и Node.js.

ES2016

ES2016 доказал процесс стандартизации, добавив всего две небольшие функции:

  1. Массив включает метод () , который возвращает истину или ложь, когда значение содержится в массиве, и
  2. Оператор a ** b степень a ** b , который идентичен Math.pow(a, b) .

ES2017

ES2017 предоставил более широкий спектр новых функций:

  • Асинхронные функции для более ясного синтаксиса Promise
  • Object.values() для извлечения массива значений из объекта, содержащего пары имя-значение
  • Object.entries() , который возвращает массив Object.entries() , содержащих имена и значения в объекте
  • Object.getOwnPropertyDescriptors() для возврата объекта, определяющего дескрипторы свойств для собственных свойств другого объекта ( .value , .writable , .get , .set , .configurable , .enumerable ).
  • padStart() и padEnd() , оба элемента заполнения строк
  • конечные запятые в определениях объектов, объявлениях массивов и списках параметров функций
  • SharedArrayBuffer и Atomics для чтения и записи в общие области памяти (отключено в ответ на уязвимость Spectre ).

Обратитесь к Что нового в ES2017 для получения дополнительной информации.

ES2018

ECMAScript 2018 (или ES9, если вы предпочитаете старую запись) теперь доступен. Следующие функции достигли стадии 4, хотя рабочие реализации будут нестабильными в разных браузерах и средах исполнения на момент написания.

Асинхронная итерация

В какой-то момент вашего асинхронного / ожидающего путешествия вы попытаетесь вызвать асинхронную функцию внутри синхронного цикла. Например:

 async function process(array) { for (let i of array) { await doSomething(i); } } 

Это не сработает. Ни один не будет это:

 async function process(array) { array.forEach(async i => { await doSomething(i); }); } 

Сами циклы остаются синхронными и всегда завершаются перед своими внутренними асинхронными операциями.

ES2018 представляет асинхронные итераторы, которые похожи на обычные итераторы, за исключением того, что метод next() возвращает Promise. Поэтому ключевое слово await может использоваться с циклами forof для последовательного запуска асинхронных операций. Например:

 async function process(array) { for await (let i of array) { doSomething(i); } } 

Promise.finally ()

Цепочка Promise может либо преуспеть и достичь финального .then() либо выйти из строя и вызвать блок .catch() . В некоторых случаях вы хотите запускать один и тот же код независимо от результата — например, для очистки, удаления диалога, закрытия соединения с базой данных и т. Д.

.finally() позволяет вам указать конечную логику в одном месте, а не дублировать ее в последних .then() и .catch() :

 function doSomething() { doSomething1() .then(doSomething2) .then(doSomething3) .catch(err => { console.log(err); }) .finally(() => { // finish here! }); } 

Отдых / Распространение Свойства

ES2015 представил остальные параметры и операторы спреда. Трехточечная ( ... ) запись применяется только к операциям с массивами. Параметры rest преобразуют последние аргументы, переданные функции в массив:

 restParam(1, 2, 3, 4, 5); function restParam(p1, p2, ...p3) { // p1 = 1 // p2 = 2 // p3 = [3, 4, 5] } 

Оператор распространения работает противоположным образом и превращает массив в отдельные аргументы, которые можно передать функции. Например, Math.max() возвращает наибольшее значение при любом количестве аргументов:

 const values = [99, 100, -1, 48, 16]; console.log( Math.max(...values) ); // 100 

ES2018 обеспечивает аналогичную функциональность отдыха / распространения для деструктуризации объектов, а также массивов. Основной пример:

 const myObject = { a: 1, b: 2, c: 3 }; const { a, ...x } = myObject; // a = 1 // x = { b: 2, c: 3 } 

Или вы можете использовать его для передачи значений в функцию:

 restParam({ a: 1, b: 2, c: 3 }); function restParam({ a, ...x }) { // a = 1 // x = { b: 2, c: 3 } } 

Как и для массивов, вы можете использовать только один параметр rest в конце объявления. Кроме того, он работает только на верхнем уровне каждого объекта, а не подобъектов.

Оператор распространения может использоваться в других объектах. Например:

 const obj1 = { a: 1, b: 2, c: 3 }; const obj2 = { ...obj1, z: 26 }; // obj2 is { a: 1, b: 2, c: 3, z: 26 } 

Вы можете использовать оператор распространения для клонирования объектов ( obj2 = { ...obj1 }; ), но имейте в obj2 = { ...obj1 }; , что вы получаете только мелкие копии. Если свойство содержит другой объект, клон будет ссылаться на тот же объект.

Именованные группы захвата регулярных выражений

Регулярные выражения JavaScript могут возвращать совпадающий объект — массивоподобное значение, содержащее совпадающие строки. Например, для разбора даты в формате ГГГГ-ММ-ДД:

 const reDate = /([0-9]{4})-([0-9]{2})-([0-9]{2})/, match = reDate.exec('2018-04-30'), year = match[1], // 2018 month = match[2], // 04 day = match[3]; // 30 

Это трудно читать, и изменение регулярного выражения также может изменить индексы объекта соответствия.

ES2018 позволяет именам групп использовать обозначение ?<name> Name ?<name> сразу после открывающей скобки ( например:

 const reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/, match = reDate.exec('2018-04-30'), year = match.groups.year, // 2018 month = match.groups.month, // 04 day = match.groups.day; // 30 

Любая именованная группа, которая не может найти соответствие, имеет свойство, установленное в undefined

Именованные захваты также могут использоваться в методах replace() . Например, преобразовать дату в американский формат MM-DD-YYYY:

 const reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/, d = '2018-04-30', usDate = d.replace(reDate, '$<month>-$<day>-$<year>'); 

Регулярные выражения смотрят за утверждениями

В настоящее время JavaScript поддерживает косвенные утверждения внутри регулярного выражения. Это означает, что совпадение должно произойти, но ничего не фиксируется, и утверждение не входит в общую совпадающую строку. Например, чтобы получить символ валюты по любой цене:

 const reLookahead = /\D(?=\d+)/, match = reLookahead.exec('$123.89'); console.log( match[0] ); // $ 

ES2018 представляет утверждения за кадром, которые работают таким же образом, но для предыдущих совпадений. Поэтому мы можем зафиксировать номер цены и игнорировать символ валюты:

 const reLookbehind = /(?<=\D)\d+/, match = reLookbehind.exec('$123.89'); console.log( match[0] ); // 123.89 

Это позитивный взгляд за утверждением; не цифра \D должна существовать. Есть также негативное утверждение за заявлением, которое устанавливает, что значение не должно существовать. Например:

 const reLookbehindNeg = /(?<!\D)\d+/, match = reLookbehind.exec('$123.89'); console.log( match[0] ); // null 

Флаг регулярного выражения s (точкаAll)

Точка регулярного выражения . соответствует любому одному символу, кроме возврата каретки. Флаг s изменяет это поведение, так что разрешаются ограничители строки. Например:

 /hello.world/s.test('hello\nworld'); // true 

Свойство Юникода регулярного выражения

До сих пор было невозможно получить доступ к свойствам символов Юникода изначально в регулярных выражениях. ES2018 добавляет экранирование свойств Unicode — в форме \p{...} и \P{...} — в регулярные выражения, для которых установлен флаг u (unicode). Например:

 const reGreekSymbol = /\p{Script=Greek}/u; reGreekSymbol.test('π'); // true 

Шаблон Литерал твик

Наконец, все синтаксические ограничения, связанные с escape-последовательностями в литералах шаблона, были удалены.

Раньше \u запускал экранирование юникода, \x запускал экранирование в шестнадцатеричном формате, а \ за которым следовала цифра, начинали восьмеричное экранирование. Это сделало невозможным создание определенных строк, таких как путь к файлу Windows C:\uuu\xxx\111 . Для получения дополнительной информации обратитесь к документации литералов шаблона MDN .

Вот и все для ES2018, но работа над ES2019 уже началась. Есть ли какие-то особенности, которые вы отчаянно хотели бы увидеть в следующем году?