5 функций ES2019, которые вы можете использовать сегодня
ECMAScript 2015, также известный как ES6, был основным релизом, для выпуска которого потребовалось шесть лет. С тех пор Технический комитет 39 (ТК39), орган, отвечающий за разработку стандарта ECMAScript, выпускает новую редакцию стандарта каждый год. Этот годовой цикл релизов упростил процесс и быстро сделал доступными новые функции, что приветствовало сообщество JavaScript.
В этом году будет выпущен ECMAScript 2019 (или ES2019 для краткости). Новые функции включают Object.fromEntries(), trimStart(), trimEnd(), flat(), flatMap(), свойство description для объектов Symbol, необязательная переменная в catch и многое другое.
Хорошей новостью является то, что эти функции уже были реализованы в последних версиях Firefox и Chrome. В этом посте мы подробно рассмотрим эти функции и посмотрим, как они обновляют язык.
1. Object.fromEntries()
Преобразование данных из одного формата в другой очень распространено в JavaScript. Чтобы упростить преобразование объектов в массивы, ES2017 ввел метод Object.entries(). Этот метод принимает объект в качестве аргумента и возвращает массив собственных перечисляемых пар свойств строкового ключа объекта в виде [key, value]. Например:
const obj = {one: 1, two: 2, three: 3}; console.log(Object.entries(obj)); // => [["one", 1], ["two", 2], ["three", 3]]
Но что, если мы хотим сделать обратное и преобразовать список пар ключ-значение в объект? Некоторые языки программирования, такие как Python, предоставляют для этого функцию dict(). В Underscore.js и Lodash также есть функция _.fromPairs.
ES2019 призван привнести аналогичную функцию в JavaScript путем введения метода Object.fromEntries(). Этот статический метод позволяет легко преобразовать список пар ключ-значение в объект:
const myArray = [['one', 1], ['two', 2], ['three', 3]]; const obj = Object.fromEntries(myArray); console.log(obj); // => {one: 1, two: 2, three: 3}
Как вы можете видеть, Object.fromEntries() — это просто противоположность Object.entries(). Хотя раньше было возможно достичь того же результата, это было не очень просто:
const myArray = [['one', 1], ['two', 2], ['three', 3]]; const obj = Array.from(myArray).reduce((acc, [key, val]) => Object.assign(acc, {[key]: val}), {}); console.log(obj); // => {one: 1, two: 2, three: 3}
Имейте в виду, что аргумент, передаваемый Object.fromEntries(), может быть любым объектом, который реализует итеративный протокол, если он возвращает двухэлементный объект в виде массива.
Например, в следующем коде Object.fromEntries() принимает объект Map в качестве аргумента и создает новый объект, ключи и соответствующие значения которого задаются парами в Map:
const map = new Map(); map.set('one', 1); map.set('two', 2); const obj = Object.fromEntries(map); console.log(obj); // => {one: 1, two: 2}
Метод Object.fromEntries() также очень полезен для преобразования объектов. Рассмотрим следующий код:
const obj = {a: 4, b: 9, c: 16}; // convert the object into an array const arr = Object.entries(obj); // get the square root of the numbers const map = arr.map(([key, val]) => [key, Math.sqrt(val)]); // convert the array back to an object const obj2 = Object.fromEntries(map); console.log(obj2); // => {a: 2, b: 3, c: 4}
Этот код преобразует значения в объекте в квадратный корень. Для этого сначала он преобразует объект в массив, а затем использует метод map() для получения квадратного корня из значений в массиве. В результате получается массив массивов, которые можно преобразовать обратно в объект.
Другая ситуация, в которой Object.fromEntries() оказывается полезной, — при работе со строкой запроса URL-адреса, как показано в следующем примере:
const paramsString = 'param1=foo¶m2=baz'; const searchParams = new URLSearchParams(paramsString); Object.fromEntries(searchParams); // => {param1: "foo", param2: "baz"}
В этом коде строка запроса передается в конструктор URLSearchParams(). Затем возвращаемое значение, которое является экземпляром объекта URLSearchParams, передается методу Object.fromEntries(). Результатом является объект, содержащий каждый параметр в качестве свойства.
Метод Object.fromEntries() в настоящее время является предложением этапа 4, что означает, что он готов для включения в стандарт ES2019.
2. trimStart() и trimEnd()
Методы trimStart() и trimEnd() технически совпадают с методами trimLeft() и trimRight(). Эти методы в настоящее время являются предложениями этапа 4 и будут добавлены в спецификацию для согласованности с padStart() и padEnd(). Давайте рассмотрим несколько примеров:
const str = " string "; // es2019 console.log(str.trimStart()); // => "string " console.log(str.trimEnd()); // => " string" // the same as console.log(str.trimLeft()); // => "string " console.log(str.trimRight()); // => " string"
Для веб-совместимости trimLeft() и trimRight() останутся псевдонимами для trimStart() и trimEnd().
3. flat() и flatMap()
Метод flat() позволяет вам легко объединять все элементы подмассива в массив. Рассмотрим следующий пример:
const arr = ['a', 'b', ['c', 'd']]; const flattened = arr.flat(); console.log(flattened); // => ["a", "b", "c", "d"]
Ранее для получения плоского массива вам пришлось бы использовать Reduce() или Concat():
const arr = ['a', 'b', ['c', 'd']]; const flattened = [].concat.apply([], arr); // or // const flattened = [].concat(...arr); console.log(flattened); // => ["a", "b", "c", "d"]
Обратите внимание, что если в предоставленном массиве есть пустые слоты, они будут отброшены:
const arr = ['a', , , 'b', ['c', 'd']]; const flattened = arr.flat(); console.log(flattened); // => ["a", "b", "c", "d"]
flat() также принимает необязательный аргумент, который задает количество уровней, на которые должен быть сведен вложенный массив. Если аргумент не указан, будет использовано значение по умолчанию 1:
const arr = [10, [20, [30]]]; console.log(arr.flat()); // => [10, 20, [30]] console.log(arr.flat(1)); // => [10, 20, [30]] console.log(arr.flat(2)); // => [10, 20, 30]
Метод flatMap() объединяет map() и flat() в один метод. Сначала он создает новый массив с возвращаемым значением предоставленной функции, а затем объединяет все элементы подмассива в массив. Пример должен сделать это более понятным:
const arr = [4.25, 19.99, 25.5]; console.log(arr.map(value => [Math.round(value)])); // => [[4], [20], [26]] console.log(arr.flatMap(value => [Math.round(value)])); // => [4, 20, 26]
Уровень глубины выравнивания массива равен 1. Если вы хотите удалить элемент из результата, просто верните пустой массив:
const arr = [[7.1], [8.1], [9.1], [10.1], [11.1]]; // do not include items bigger than 9 arr.flatMap(value => { if (value >= 10) { return []; } else { return Math.round(value); } }); // returns: // => [7, 8, 9]
Помимо текущего обрабатываемого элемента, функция обратного вызова также получит индекс элемента и ссылку на сам массив. Методы flat() и flatMap() в настоящее время являются предложениями этапа 4.
4. Описание свойства для объектов Symbol
При создании Symbol вы можете добавить описание для отладки. Иногда полезно иметь прямой доступ к описанию в вашем коде.
Это предложение ES2019 добавляет свойство описания только для чтения к объекту Symbol, которое возвращает строку, содержащую описание Symbol. Вот некоторые примеры:
let sym = Symbol('foo'); console.log(sym.description); // => foo sym = Symbol(); console.log(sym.description); // => undefined // create a global symbol sym = Symbol.for('bar'); console.log(sym.description); // => bar
5. Опциональная переменная в catch
Переменная в catch в выражении try… catch теперь будет опциональным. Рассмотрим следующий код:
try { // использовать функцию, которую браузер, возможно, не реализовал } catch (unused) { // вернуться к уже реализованной функции }
В этом коде нет смысла для переменной unused в catch. Тем не менее, он все еще должен использоваться, чтобы избежать SyntaxError. Это предложение вносит небольшое изменение в спецификацию ECMAScript, которая позволяет вам пропустить переменную в catch и окружающие ее скобки:
try { // использовать функцию, которую браузер, возможно, не реализовал } catch { // сделать что-то, что не заботится о значение thrown }
Бонус: ES2020 String.prototype.matchAll
Метод matchAll() является предложением ES2020 этапа 4, которое возвращает объект итератора для всех совпадений, включая группы захвата, для регулярного выражения.
Для согласованности с методом match() TC39 выбрал «matchAll» среди других предложенных имен, таких как «matches» или «scan» Руби. Давайте рассмотрим простой пример:
const re = /(Dr\. )\w+/g; const str = 'Dr. Smith and Dr. Anderson'; const matches = str.matchAll(re); for (const match of matches) { console.log(match); } // logs: // => ["Dr. Smith", "Dr. ", index: 0, input: "Dr. Smith and Dr. Anderson", groups: undefined] // => ["Dr. Anderson", "Dr. ", index: 14, input: "Dr. Smith and Dr. Anderson", groups: undefined]
Группа захвата в этом регулярном выражении соответствует символам «Dr», за которыми следуют точка и пробел. \w+ соответствует любому символу слова один или несколько раз. А флаг g указывает движку искать шаблон по всей строке.
Раньше вам приходилось использовать метод exec() в цикле для достижения того же результата, что было не очень эффективно:
const re = /(Dr\.) \w+/g; const str = 'Dr. Smith and Dr. Anderson'; let matches; while ((matches = re.exec(str)) !== null) { console.log(matches); } // logs: // => ["Dr. Smith", "Dr.", index: 0, input: "Dr. Smith and Dr. Anderson", groups: undefined] // => ["Dr. Anderson", "Dr.", index: 14, input: "Dr. Smith and Dr. Anderson", groups: undefined]
Важно отметить, что хотя метод match() можно использовать с глобальным флагом g для доступа ко всем совпадениям, он не предоставляет группы захвата или индексную позицию совпадений. Для сравнения:
const re = /page (\d+)/g; const str = 'page 2 and page 10'; console.log(str.match(re)); // => ["page 2", "page 10"] console.log(...str.matchAll(re)); // => ["page 2", "2", index: 0, input: "page 2 and page 10", groups: undefined] // => ["page 10", "10", index: 11, input: "page 2 and page 10", groups: undefined]
Завершение
В этой статье мы подробно рассмотрели несколько ключевых функций, представленных в ES2019, включая Object.fromEntries(), trimStart(), trimEnd(), flat(), flatMap(), свойство description для объектов Symbol и необязательная переменная в catch.
Несмотря на то, что некоторые функции браузеров еще не полностью реализовали эти функции, вы все равно можете использовать их в своих проектах благодаря Babel и другим транспортерам JavaScript.
Темпы развития ECMAScript в последние годы ускорились, и новые функции внедряются и внедряются время от времени, поэтому обязательно ознакомьтесь со списком готовых предложений, чтобы быть в курсе того, что нового. У вас есть несколько советов? Поделитесь ими в комментариях!
Оригинальная статья: Faraz Kelhini 5 ES2019 features you can use today