[Перевод] Обзор новшеств ECMAScript 2016, 2017, и 2018 с примерами

Сложно уследить за новшествами различных версий ECMAScript, а ещё сложнее — найти полезные примеры их применения, не перекапывая горы информации. Поэтому сегодня мы публикуем перевод материала, автор которого проанализировал 18 новых возможностей ECMAScript, в число которых входят те, что имеются в уже вышедших стандартах ES2016 и ES2017, а также — те, которые должны появиться в стандарте ES2018. Автор этой статьи обещает, что каждый, кто её прочтёт, узнает много интересного и полезного о новых возможностях JavaScript.

m855gbdmzocg6axivr2rnuhietu.png

ECMAScript 2016


RQldeAUfY-BkPu99klhWBuhgGy4HIxVI1vkQLQ86


▍1. Array.prototype.includes ()


Метод includes — это простой метод объектов типа Array, который позволяет выяснить, имеется ли в массиве некий элемент (он, в отличие от indexOf, подходит и для работы со значениями NaN).

nkREO2CfjgBB8X6dnUKzNSPYOTO4YRfhYY_rZOiv


ECMAScript 2016 (ES7) — пример использования Array.prototype.includes ()

Интересно то, что сначала этот метод хотели назвать contains, но оказалось, что такое название уже используется в Mootools, в результате было принято решение использовать имя includes.

▍2. Инфиксный оператор возведения в степень


Математические операции, вроде сложения и вычитания, реализуются в JavaScript с помощью инфиксных операторов, таких, как, соответственно,»+» и »-». Существует и нашедший широкое применение в программировании инфиксный оператор, который используется для возведения в степень. Такой оператор, выглядящий как »**», был представлен в ECMAScript 2016, он может служить заменой Math.pow().

2h6Zhf4r9cAzr-vGoWWNbqQXAiDiq1lWcYEAyvLV


ECMAScript 2016 (ES7) — использование инфиксного оператора возведения в степень

ECMAScript 2017


fT7JVk_w550IreVilZU142E05pkjNezVFvuOQDHj


▍1. Object.values ()


Метод Object.values() — это новая функция, которая похожа на Object.keys(), но возвращает все значения собственных свойств объекта, исключая любые значения в цепочке прототипов.

IKvm7iy2iPcLaXHzxNFWhnykoj_1vdWTarVg1Z3f


ECMAScript 2017 (ES8) — использование Object.values ()

▍2. Object.entries ()


Метод Object.entries() похож на метод Object.keys(), но вместо того, чтобы возвращать лишь ключи, он возвращает, в виде массива, и ключи, и значения. Это упрощает выполнение операций, предусматривающих использование объектов в циклах, или операций преобразования обычных объектов в объекты типа Map.

Вот первый пример использования этого метода.

DvoPXyEae8Du-fokFoAZnA2nFqiLfw33FLYzHDj7


ECMAScript 2017 (ES8) —  использование Object.entries () в циклах

Вот второй пример.

qt8aah90zJn3HGYSMr0iauFekmy-7DaYorOqbYaN


ECMAScript 2017 (ES8) —  использование Object.entries () для преобразования объекта типа Object в объект типа Map

▍3. Дополнение строк до заданной длины


У объектов типа String теперь есть два новых метода: String.prototype.padStart() и String.prototype.padEnd(). Они позволяют присоединять к строкам, в их начало или конец, некоторое количество символов для дополнения строк до заданной длины.

'someString'.padStart(numberOfCharcters [,stringForPadding]); 
'5'.padStart(10) // '          5'
'5'.padStart(10, '=*') //'=*=*=*=*=5'
'5'.padEnd(10) // '5         '
'5'.padEnd(10, '=*') //'5=*=*=*=*='


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

3.1 Пример работы с padStart ()


В следующем примере у нас имеется список чисел разной длины. Мы хотим добавить в начало этих чисел »0», причём, таким образом, чтобы сделать все их состоящими из 10 цифр. Нужно это для того, чтобы аккуратно вывести их на экран. Для того чтобы решить эту задачу, мы можем воспользоваться командой padStart(10, '0').

boPFWaELOergPoxtDHZShvtR6IGyZBgwxJP2sU2P


ECMAScript 2017 — пример использования padStart ()

3.2 Пример работы с padEnd ()


Метод padEnd() оказывается весьма полезным при выводе на экран множества строк разной длины, которые нужно выровнять по правому краю страницы.

В следующем примере показано совместное использование методов padEnd(), padStart(), и Object.entries() для формирования строк, которые хорошо смотрятся при выводе на экран.

7694KmGvP7ddVufYotixEn_xTAJvZhA8w_yb938A


ECMAScript 2017 —  пример использования padEnd (), padStart () и Object.Entries ()

3.3. Использование padStart () и padEnd () с эмотиконами и другими двухбайтовыми символами


Эмотиконы и другие двухбайтовые символы представлены в кодировке Unicode последовательностями из нескольких байтов. Поэтому методы padStart() и padEnd() работают с ними не так, как того можно ожидать.

Например, предположим, что мы хотим сделать так, чтобы длина строки heart оказалась равной 10 символам путём добавления к ней эмотикона . Результат, при обычно подходе, будет выглядеть так:

//Обратите внимание на то, что вместо 5 сердечек тут лишь 2 таких, которые нам нужны, и одно, выглядящее не так, как ожидается
'heart'.padStart(10, "️"); // при выводе получается '️️heart'


Проблема тут в том, что то сердечко, которым мы хотим дополнить строку, представлено двухбайтовым кодом '\u2764\uFE0F'. Слово heart имеет длину 5 символов и для дополнения этой строки до длины 10 у нас остаётся лишь 5 свободных мест. В результате JS добавляет к строке два эмотикона, используя код '\u2764\uFE0F', занимающий четыре свободных места, что даёт два значка сердца. Последнее свободное место заполняется первым байтом, символом с кодом '\u2764', который как раз и даёт то сердце, которое выглядит не так, как остальные.

Вот, кстати, страница, которой можно воспользоваться для работы с символами Unicode.

▍4. Object.getOwnPropertyDescriptors ()


Этот метод возвращает все сведения (включая данные о геттерах и сеттерах) для всех свойств заданного объекта. Главная причина добавления этого метода заключается в том, чтобы позволить создавать мелкие копии объектов и клонировать объекты, создавая новые объекты, при этом копируя, помимо прочего, геттеры и сеттеры. Метод Object.assign() этого не умеет. Он позволяет выполнять мелкие копии объектов, но не работает с их геттерами и сеттерами.

В следующих примерах показана разница между Object.assign() и Object.getOwnPropertyDescriptors(), а также продемонстрировано использование метода Object.defineProperties() для копирования исходного объекта car в новый объект, ElectricCar. Тут можно заметить, что благодаря использованию Object.getOwnPropertyDescriptors(), функция discount, играющая роль и геттера, и сеттера, также копируется в целевой объект.

Итак, до появления Object.getOwnPropertyDescriptors() копирование объектов выглядело так. Тут можно заметить, что при копировании объекта данные о геттерах и сеттерах теряются.

-pOEV3AxkBrJ2onfLiQDkcnu083647lVZ5B-xAwA


Копирование объектов с использованием Object.assign ()

Вот как выглядит выполнение той же операции, но уже с использованием Object.getOwnPropertyDescriptors().

nOkAP7vQ6caVfYpqvPbaHE2rmEU34VGa9oUIGQ6R


ECMAScript 2017 (ES8) —  использование Object.getOwnPropertyDescriptors ()

▍5. Завершающие запятые в параметрах функций


Это небольшое обновление, которое позволяет ставить запятую после последнего параметра функции. Зачем это нужно? Например, для того, чтобы помочь при работе с инструментами вроде git blame, избавляя разработчиков, вносящих изменения в код, от необходимости менять (без особой нужды в данном случае) строки, написанные тем, кто работал над этим кодом раньше.

В следующем примере показана проблема редактирования кода и её решение с помощью запятой, которая находится за последним параметром функции.

92rQB5oLVbsaTdW5UFNIYsieqAORWL6uywbFFVUj


ECMAScript 2017 (ES8) — запятая, поставленная после последнего параметра функции, облегчает редактирование кода

▍6. Конструкция Async/Await


Это нововведение я назвал бы самым важным и самым полезным. Асинхронные функции позволяют избавиться от так называемого «ада коллбэков» и улучшить внешний вид и читаемость кода.
Ключевое слово async сообщает JavaScript-интерпретатору о том, что функцию, объявленную с этим ключевым словом, нужно воспринимать по-особому. Систем приостанавливается, достигая ключевого слова await в этой функции. Она считает, что выражение после await возвращает промис и ожидает разрешения или отклонения этого промиса перед продолжением.

В следующем примере функция getAmount() вызывает две асинхронные функции — getUser() и getBankBalance(). Сделать это можно и в промисе, но использование конструкции async/await позволяет решить эту задачу проще и элегантнее.

xc9FSQb_mAf0b6wiefv1sCDoRCC0soBUnHk_tc4D


ECMAScript 2017 (ES 8) — простой пример использования конструкции Async/Await

6.1. Асинхронные функции и возврат промисов


Если вы ожидаете результата от функции, объявленной с использованием ключевого слова async, вам нужно будет использовать выражение промиса .then() для того, чтобы этот результат получить.

В следующем примере мы хотим вывести результат в консоль, используя команду console.log(), но сделать это нужно за пределами функции doubleAndAdd(). Поэтому нам нужно подождать, используя .then(), для того, чтобы передать полученный результат console.log().

SgwfO_uigCp45uuSwY7u9sPaNkkV7J6IfUmpsVse


ECMAScript 2017 (ES 8) — демонстрация возврата промиса конструкцией async/await

6.2. Параллельный вызов функций с использованием async/await


В предыдущем примере мы дважды пользуемся ключевым словом await, каждый раз ожидая завершения операции в течение одной секунды (общее время ожидания — 2 секунды). Вместо этого мы можем распараллелить выполнения задач, так как a и b не зависят друг от друга. Сделать это можно с помощью конструкции Promise.all().

H0h9nKO3cgFORWkM_7rbSJpRdv2hPxQSrR6MSu6t


ECMAScript 2017 (ES 8) — использование Promise.all для параллельного выполнения await-команд

6.3. Обработка ошибок при использовании конструкции async/await


Существуют различные способы обработки ошибок при использовании конструкции async/await.

Вариант 1: использование try/catch внутри функции

wYwUuEf_qyvGmdJz8krnvKzw652TVdBA2N0uLd8K


ECMAScript 2017 —  использование try/catch внутри конструкции async/await

Вариант 2: использование catch в каждом выражении await

Так как каждое выражение await возвращает промис, перехватывать ошибки можно в каждом таком выражении.

Z7MqHCBrnoe86E_XBzfMzbEPW8isE4Jlx0lwFRQC


ECMAScript 2017 — Использование конструкции catch с каждым выражением await

Вариант 3: использование конструкции catch для всей async/await-функции

-uo3Bzdb0ZxsWh3oYPcKSpKXEBZkl-9UOmYZcnY4


ECMAScript 2017 —  перехват ошибок во всей асинхронной функции

ECMAScript 2018


EUo9wDVc3GKiiTUSiOLrrD8Ib4vyMe_AYplA7yhY

ECMAScript 2018 сейчас находится на стадии final draft, выход стандарта ожидается в июне-июле 2018 года. Все возможности, рассмотренные ниже, находятся на этапе Stage-4 и станут частью ECMAScript 2018.

▍1. Разделяемая память и атомарные операции


Разделяемая память (shared memory) и атомарные операции (atomics) — это потрясающая, весьма продвинутая возможность, затрагивающая ядро JS-движков.

Основная идея этой возможности заключается в том, чтобы позволить JS-разработчикам писать высокопроизводительные параллельные приложения, дать им возможность управлять памятью самостоятельно, не отдавая выполнение всех аспектов этой задачи JS-движку.

Реализовано это с помощью глобального объекта нового типа, который называется SharedArrayBuffer. Его основная задача заключается в хранении данных в разделяемом пространстве памяти. В результате такими данными могут совместно пользоваться главный поток JS и потоки веб-воркеров.

До настоящего момента, если нам нужно было организовать обмен данными между главным потоком и веб-воркером, нам приходилось создавать копии данных и отправлять их с помощью функции postMessage(). Теперь же всё будет уже не так, как раньше.

Благодаря использованию SharedArrayBuffer разные потоки могут получать доступ к данным практически мгновенно. Однако общий доступ к памяти из разных потоков может вызвать состояние гонок. Для того чтобы избежать этого состояния, предусмотрен глобальный объект Atomics. Он предоставляет различные методы для блокирования разделяемой памяти на время выполнения операций с ней из конкретного потока. Он, кроме того, даёт методы для безопасного обновления данных в разделяемой памяти.

Обычно этой возможностью не рекомендуют пользоваться напрямую, говоря о том, что лучше будет применять библиотеки, построенные на базе SharedArrayBuffer. Однако такие библиотеки пока не написаны.

Если вам интересна эта тема — вот, вот и вот — несколько полезных материалов.

▍2. Устранение ограничений тегированных шаблонных строк


Для начала разберёмся с понятием «тегированная шаблонная строка» (или «тегированный шаблон») для того, чтобы лучше понять эту новую возможность.

В ES2015+ есть возможность, называемая тегированным шаблоном, которая позволяет разработчикам настраивать интерполяцию строк. Например, при стандартном подходе это выглядит так.

zpM4rAJoBropXp37BFVi9yArHR_n06HWYVV4m9nL


Стандартный вариант использования шаблонных строк

При использовании тегированных шаблонов можно написать функцию, принимающую, как параметры, неизменную часть строкового литерала, например, [ ‘Hello ‘, ‘!’ ] и переменные для замены, например, [ 'Raja']. Например, пусть это будет функция greet. Такая функция может возвращать то, что нужно разработчику.

В следующем примере показано, как наше собственное теговое выражение, функция, присоединяет к строке приветствие, основываясь на времени суток (например — «Good Morning!» или «Good afternoon») и возвращает готовую строку.

jARnEDTE0jb1Q2-JLdDT1WvXp5rFbSSXL5QU1Ww5


Пример тегового выражения, функции, которая демонстрирует настраиваемое дополнение строк

Узнав о тегированных шаблонных строках, многие стремятся использовать эту возможность в различных сферах, например, для работы с командами в терминале или при создании URL для выполнения HTTP-запросов. Однако, тут нужно учитывать одно важное ограничение. Оно заключается в том, что ES2015 и ES2016 позволяют использовать лишь управляющие последовательности вроде "\u" (unicode), "\x"(hexadecimal), которые формируют нечто такое, что понятно системе, например, `\u00A9` или \u{2F804} или \xA9.

Поэтому, если имеется тегированная функция, внутри которой используются правила из другой области (например, при работе с терминалом), где может понадобиться использовать что-то вроде \ubla123abla, что не выглядит с точки зрения системы правильным кодом, появится сообщение об ошибке.

В ES2018 ограничения ослаблены. Теперь можно использовать конструкции, выглядящие как неправильные управляющие последовательности, возвращая значения в объекте, одно свойство которого («cooked» в нашем примере), содержит undefined, а второе («raw») содержит то, что нам нужно.

function myTagFunc(str) { 
 return { "cooked": "undefined", "raw": str.raw[0] }
} 

var str = myTagFunc `hi \ubla123abla`; //вызов myTagFunc

str // { cooked: "undefined", raw: "hi \\ubla123abla" }


▍3. Флаг регулярных выражений dotAll


Сейчас, при использовании регулярных выражений, хотя считается, что символ точки соответствует любому одиночному символу, он не соответствует символам перевода строки вроде \n\r \f и так далее.

Например, до этого нововведения всё выглядело так:

/first.second/.test('first\nsecond'); //false


Благодаря данному улучшению точка теперь соответствует абсолютно любому символу. Для того, чтобы старые регулярные выражения продолжали бы работать так, как раньше, при создании регулярных выражений, следующих новым правилам, нужно использовать флаг \s.

//ECMAScript 2018
/first.second/s.test('first\nsecond'); //true - обратите внимание на /s


Вот API этого предложения из документации.

VZRVhQiDgNF5iY0u9f8NEeockQsttx0ElS7yKLpw


ECMAScript 2018 — теперь, благодаря флагу /s, можно сделать так, чтобы точка в регулярных выражениях соответствовала абсолютно всем символам, включая \n

▍4. Захват именованных групп в регулярных выражениях


Это улучшение представляет собой полезную возможность регулярных выражений, которая имеется в других языках вроде Python и Java. Речь идёт об именованных группах. Эта возможность позволяет разработчикам писать регулярные выражения с назначением имён (идентификаторов) в формате (?...) для групп. Это имя облегчает работу с группами.

4.1. Базовый пример работы с именованными группами


В следующем примере мы используем имена (?), (?) и (?day) для группировки различных частей даты, с которой мы работаем с использованием регулярного выражения. Итоговый объект при таком подходе будет содержать свойство groups, которое будет иметь свойства year, month и day с соответствующими значениями.

TW6TQFGcWUSArThGtDX9l5L44JIlWp-QfAAV70PH


ECMAScript 2018 — пример работы с именованными группами

4.2. Использование именованных групп внутри регулярного выражения


Мы можем использовать конструкции вида \k для того, чтобы ссылаться на группы внутри самого регулярного выражения. Эта техника продемонстрирована в следующем примере.

uvmyYZLf-aX9AeqDXmvnCyURM7d8q3mo5BKd0xzP


ECMAScript 2018 —  использование именованных групп внутри регулярного выражения с применением конструкции \k

4.3. Использование именованных групп в String.prototype.replace ()


еперь возможность использования именованных групп встроена в метод строк replace(). Это позволяет, например, организовать перестановку слов в строках. Например, вот как изменить строку "firstName, lastName" на "lastName, firstName".

yrbp293mgFh3l9Rs7U1odjARadccvHdD54RdhuIF


ECMAScript 2018 — использование именованных групп регулярных выражений в строковом методе replace ()

▍5. Работа со свойствами объектов с использованием оператора rest


Оператор rest, выглядящий как три точки, позволяет извлекать свойства объекта, которые пока из него не извлечены.

5.1. Извлечение из объекта только необходимых свойств


HMIMujftPcKGJoJuoLOky9Xgd_oxJ3Xrh8-jlpen


ECMAScript 2018 —  деструктурирование объекта с помощью оператора rest

5.2. Удаление ненужных свойств объектов


LkpOf2BDyMqqSgIXpM119qmtuUblPeliDk16e2Sm


ECMAScript 2018 —  удаление ненужных свойств объектов

▍6. Работа со свойствами объектов с использованием оператора spread


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

Оператор spread используется в правой части выражения со знаком присваивания. Оператор rest используется в левой части выражения.

ZuTimrfQ45CKTrtJv7BVvji5-IJjkLsNJ8iLD2UM


ECMAScript 2018 — создание объекта с использованием оператора rest

▍7. Ретроспективная проверка в регулярных выражениях


Ретроспективная проверка в регулярных выражениях позволяет узнать, существует ли некая строка сразу перед некоторой другой строкой.

Теперь для того, чтобы произвести положительную ретроспективную проверку, можно использовать группу вида (?<=…) (знак вопроса, знак «меньше» и знак равенства).

Далее, можно использовать группу вида (?>!…) (знак вопроса, знак «меньше», восклицательный знак) для выполнения отрицательной ретроспективной проверки. Поиск при таком подходе продолжается только в том случае, если слева от текущей позиции в тексте отсутствует выражение, указанное в скобках.

Рассмотрим пример положительной ретроспективной проверки. Предположим, нам надо проверить, находится ли символ # перед словом winning (то есть, нас интересует конструкция вида #winning), при этом нужно, чтобы регулярное выражение вернуло лишь строку «winning». Вот как можно этого достичь.

FgngAjSTvemLqZELauvkTGxmJYscH14_jZrkIQqw


ECMAScript 2018 — использование конструкции (? <=…) для положительной ретроспективной проверки

Рассмотрим пример отрицательной ретроспективной проверки. Предположим, нам нужно извлечь из строки числа, перед которыми стоит знак , но не знак $. Вот как это сделать.

TsshU1N9ucahdEPOlMi3MNfT8L2EU3iFuPOk113Z


EMAScript 2018 — использование конструкции (?

▍8. Использование управляющих последовательностей Unicode в регулярных выражениях


Раньше писать регулярные выражения, направленные на анализ Unicode-символов, было непросто. Конструкции вида \w, \W, \d помогали лишь в работе с латинскими символами и цифрами. А как быть с символами других языков, вроде хинди или греческого?

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

Например база данных Unicode группирует все символы хинди (например — हिन्दी, здесь, кстати, три символа) по свойству Script со значением Devanagari, и по ещё одному свойству, которое выглядит как Script_Extensions, с тем же значением. Это позволяет нам выполнить поиск по значению Script=Devanagari и получить все символы хинди.

Unicode-блок Devanagari может использоваться для различных индийских языков, таких, как маратхи, хинди, санскрит и других.

Начиная с ECMAScript 2018 можно использовать конструкцию вида \p{Script=Devanagari} для поиска символов всех языков письменности деванагари. Такая конструкция позволяет работать со всеми подобными символами.

8BH7rtw5rlW2nE06iNQLf5VsQYXjUN3kfUhKoqXL


ECMAScript 2018 — использование возможности по работе с Unicode-символами письменности деванагари

Похожим образом, все греческие символы собраны в группе Script_Extensions (Script) со значением Greek. Это даёт возможность выполнять поиск греческих символов с использованием конструкции вида Script_Extensions=Greek или Script=Greek.

Вот как с помощью конструкции \p{Script=Greek} искать греческие символы.

VppppIMk7aBYsk38oeoH26yO4Z3BmEwWuyfDY5Zh


ECMAScript 2018 — использование возможности по работе с греческими символами

Далее, база данных Unicode хранит различные типы эмотиконов в блоках Emoji, Emoji_Component, Emoji_Presentation, Emoji_Modifier, и Emoji_Modifier_Base со свойством true. Это даёт возможность искать эмотиконы, просто используя свойство Emoji.

Таким образом, мы можем использовать конструкции вида \p{Emoji} и \p{Emoji_Modifier} для поиска эмотиконов различных видов. Вот соответствующий пример.

MKYrZ4JW4_CDKkRCeBBjtPAO1WiLP_Gjl_RqTGsH


ECMAScript 2018 — поиск различных эмотиконов

И, наконец, мы можем использовать управляющую последовательность, представленную заглавной буквой P (\P) вместо прописной p (\p) для проверки строк на отсутствие совпадений.

▍9. Promise.prototype.finally ()


Метод finally() — это новый метод объектов Promise. Основное назначение этого метода заключается в том, чтобы позволить выполнять функцию обратного вызова после resolve() или reject() для того, чтобы корректно завершать операции, например, высвобождая ресурсы там, где это необходимо. Коллбэк finally() вызывается без какого-либо значения, он выполняется в любом случае.

Рассмотрим различные варианты его использования.

ZPiENiHS55NUtgrgXSowybt0vbzP9n4I7phAkE5M


ECMAScript 2018 —  использование finally () в случае вызова resolve ()

saPqpZbCQ_73Pz50PNtGxdZozjydE4F8E8XZjs98


ECMAScript 2018 —  использование finally () в случае вызова reject ()

lAXhPRFdmntfN85a3YWIFN1NSVZnHJKOQ9pV4jjB


ECMAScript 2018 —  использование finally () при возникновении ошибки

HUJBWZ4VtymxGZpAeqFHyvM06EJZbv8pqxoDbfYQ


ECMAScript 2018 —  использование finally () при возникновении ошибки в выражении catch ()

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


Это — просто невероятно полезная возможность. Она позволяет без труда создавать циклы, работающие с асинхронным кодом.

В рамках этой возможности добавляется новый оператор цикла вида for-await-of, который позволяет вызывать асинхронные функции, возвращающие промисы (или обрабатывать массивы, содержащие промисы) в цикле. Самое интересное здесь то, что цикл ждёт разрешения каждого промиса перед переходом к следующему шагу.

gtmKg7yF1Xr1gUXcP2D60UPccc-liGKo1cUo7ckF


ECMAScript 2018 — использование нового цикла for-await-of

Итоги


В этом материале были рассмотрены новшества ES2016, ES2017 и ES2018, а так же были приведены примеры использования данных конструкций. Надеемся, это пригодится всем, кто хочет упорядочить свои знания в области новых и ожидаемых возможностей JavaScript и поможет продуктивно их использовать.

Уважаемые читатели! Какие новшества ES2016, ES2017 и ES2018 кажутся вам наиболее полезными?

1ba550d25e8846ce8805de564da6aa63.png

© Habrahabr.ru