Перейти к основному содержимому

9 записей с тегом "ES2019"

Посмотреть все теги

Подмножество JSON, также известное как JSON ⊂ ECMAScript

· 6 мин. чтения
Матиас Биненс ([@mathias](https://twitter.com/mathias))

Благодаря предложению JSON ⊂ ECMAScript, JSON стал синтаксическим подмножеством ECMAScript. Если вас удивляет, что это не было так ранее, вы не одиноки!

Старое поведение из ES2018

В ES2018 строковые литералы ECMAScript не могли содержать неизбежные символы U+2028 LINE SEPARATOR и U+2029 PARAGRAPH SEPARATOR, поскольку они считаются разделителями строк даже в таком контексте:

// Строка, содержащая необработанный символ U+2028.
const LS = '
';
// → ES2018: SyntaxError

// Строка, содержащая необработанный символ U+2029, созданная с помощью `eval`:
const PS = eval('"\u2029"');
// → ES2018: SyntaxError

Это проблематично, потому что строки JSON могут содержать эти символы. В результате разработчики были вынуждены реализовать специальную логику постобработки при встраивании допустимого JSON в программы ECMAScript для обработки этих символов. Без такой логики в коде могли быть тонкие ошибки или даже проблемы безопасности!

Стабильная `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 },
];
// Сортируем собак по рейтингу в порядке убывания.
// (Это обновляет `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('')).

`Object.fromEntries`

· 3 мин. чтения
Матиас Биненс ([@mathias](https://twitter.com/mathias)), шептун JavaScript

Object.fromEntries — это полезное дополнение к встроенной библиотеке JavaScript. Перед тем как объяснить, что он делает, важно понять существующий API Object.entries.

Object.entries

API Object.entries существует уже некоторое время.

Для каждой пары ключ-значение в объекте 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(`Значение ${key} равно ${value}.`);
}
// Результат:
// Значение x равно 42.
// Значение y равно 50.

К сожалению, нет простого способа преобразовать результат entries обратно в эквивалентный объект… до настоящего момента!

Object.fromEntries

Новый API Object.fromEntries выполняет обратное преобразование от Object.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 }

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

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, то есть только ключи x и y, исключая ключ abc. Затем мы преобразуем оставшиеся пары и возвращаем обновленные пары ключ-значение для каждой. В этом примере мы удваиваем каждое значение, умножая его на 2. Конечный результат — новый объект, содержащий только свойства x и y с новыми значениями.

`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.flat, а не Array.prototype.flatten? Прочтите наш разбор #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? Ознакомьтесь с объяснением Акселя Раушмайера.

Поддержка Array#{flat,flatMap}

Хорошо сформированный `JSON.stringify`

· 1 мин. чтения
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JSON.stringify ранее был определен так, что возвращал некорректные строки Unicode, если входные данные содержали одиночные суррогаты:

JSON.stringify('\uD800');
// → '"�"'

Предложение «хорошо сформированного JSON.stringify» изменяет JSON.stringify, чтобы он выводил экранированные последовательности для одиночных суррогатов, делая его вывод валидным Unicode (и представимым в UTF-8):

Необязательное связывание `catch`

· 1 мин. чтения
Матиас Байненс ([@mathias](https://twitter.com/mathias))

Конструкция catch в инструкции try ранее требовала связывание:

try {
doSomethingThatMightThrow();
} catch (exception) {
// ^^^^^^^^^
// Мы должны указать связывание, даже если не используем его!
handleException();
}

В ES2019 catch теперь может использоваться без связывания. Это полезно, если объект exception не требуется в коде, обрабатывающем исключение.

try {
doSomethingThatMightThrow();
} catch { // → Без связывания!
handleException();
}

Поддержка необязательного связывания catch

Методы `String.prototype.trimStart` и `String.prototype.trimEnd`

· 1 мин. чтения
Матиас Байненс ([@mathias](https://twitter.com/mathias))

ES2019 представляет String.prototype.trimStart() и String.prototype.trimEnd():

const string = '  hello world  ';
string.trimStart();
// → 'hello world '
string.trimEnd();
// → ' hello world'
string.trim(); // ES5
// → 'hello world'

Эта функциональность ранее была доступна через нестандартные методы trimLeft() и trimRight(), которые остаются алиасами для новых методов для обратной совместимости.

const string = '  hello world  ';
string.trimStart();
// → 'hello world '
string.trimLeft();
// → 'hello world '
string.trimEnd();
// → ' hello world'
string.trimRight();
// → ' hello world'
string.trim(); // ES5
// → 'hello world'

Обновленный `Function.prototype.toString`

· 1 мин. чтения
Матиас Биненс ([@mathias](https://twitter.com/mathias))

Function.prototype.toString() теперь возвращает точно такие же фрагменты текста исходного кода, включая пробелы и комментарии. Вот пример, сравнивающий старое и новое поведение: