javascript

ES8: основные новшества

  • пятница, 14 июля 2017 г. в 03:12:35
https://habrahabr.ru/company/ruvds/blog/332998/
  • JavaScript
  • Блог компании RUVDS.com


В общем-то, тема новшеств в EcmaScript постоянно на слуху. Это далеко не случайно, так как новые стандарты, с некоторых пор, выходят ежегодно. Стандарт ES6 появился в 2015-м, ES7 — в 2016-м. Но вряд ли кто сразу вспомнит, когда вышел ES5, так как случилось это в 2009-м году, до эпохи бурного роста и развития JavaScript. Пожалуй, каждый JS-разработчик наблюдает за развитием языка. Сегодня пришло время поговорить о том, что принёс нам ES8.

image

Если вы не ищете лёгких путей — можете сразу перейти к веб-версии или к PDF-варианту нового стандарта. Кроме того, полезные сведения о возможностях ES8 можно найти на сайте MDN, материалы которого использовались и при подготовке этого обзора. Тех же, кто хочет быстро ознакомиться с основными нововведениями ES8 и взглянуть на примеры кода, приглашаем под кат.

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


Эта возможность реализована с помощью двух методов объекта String: padStart() и padEnd(). Слова «Начало» и «Конец» в названиях функций намекают на их роли в деле обработки строк. А именно, они позволяют задавать параметры дополнения строк до достижения ими заданной длины. Метод padStart() дополняет строку с её начала (слева), padEnd() — с конца (справа). Строки можно дополнять заданными одиночными символами, другими строками, или, по умолчанию, пробелами. Вот синтаксис функций, о которых идёт речь:

str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])

Как видите, первый параметр этих функций — targetLength. Он представляет собой целевую длину результирующей строки. Второй параметр, необязательный padString, это строка, которой будет дополняться исходная строка. Без указания этого параметра для дополнения будет использоваться пробел. Если длина строки, к которой применяется один из этих методов, превышает заданную, исходная строка остаётся неизменной.

Вот несколько примеров:

'es8'.padStart(2);          // 'es8'
'es8'.padStart(5);          // '  es8'
'es8'.padStart(6, 'woof');  // 'wooes8'
'es8'.padStart(14, 'wow');  // 'wowwowwowwoes8'
'es8'.padStart(7, '0');     // '0000es8'

'es8'.padEnd(2);          // 'es8'
'es8'.padEnd(5);          // 'es8  '
'es8'.padEnd(6, 'woof');  // 'es8woo'
'es8'.padEnd(14, 'wow');  // 'es8wowwowwowwo'
'es8'.padEnd(7, '6');     // 'es86666'


Поддержка в браузерах (MDN)

Методы Object.values() и Object.entries()


Метод Object.values() возвращает массив собственных перечисляемых свойств переданного ему объекта в том же порядке, в котором это делает цикл for…in. Синтаксис метода предельно прост:

Object.values(obj)

Параметр obj — это тот объект, свойства которого надо получить. Он может быть объектом или массивом (иными словами, объектом с индексами наподобие [10, 20, 30] -> { 0: 10, 1: 20, 2: 30 }). Вот пример кода:

const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]

const obj = ['e', 's', '8']; // то же самое, что и { 0: 'e', 1: 's', 2: '8' };
Object.values(obj); // ['e', 's', '8']


Поддержка Object.values() в браузерах (MDN)

Метод Object.entries() возвращает массив собственных перечисляемых свойств объекта в формате [ключ, значение], в том же порядке, что и Object.values(). Синтаксис метода аналогичен Object.values(), да и в остальном эти методы похожи:

Object.entries(obj)

Вот примеры:

const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]

const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]

const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]


Поддержка Object.entries() в браузерах (MDN)

Метод Object.getOwnPropertyDescriptors()


Метод Object.getOwnPropertyDescriptors() возвращает дескриптор собственного свойства переданного объекта. Собственное свойство определено непосредственно в объекте, а не получено через цепочку прототипов. Вот синтаксис метода:

Object.getOwnPropertyDescriptor(obj, prop)

Аргумент obj — это объект, данные по свойству которого надо получить, аргумент prop — это имя свойства, дескриптор которого нас интересует. В результате успешного выполнения этого метода будет возвращён объект, в котором могут быть следующие ключи:

  • configurable — true — если тип дескриптора свойства может быть изменён и если свойство может быть удалено из содержащего его объекта, иначе false.

  • enumerabletrue — если свойство доступно при перечислении свойств объекта, иначе — false.

  • writabletrue — если значение ассоциированное со свойством, может быть изменено, иначе false (для дескрипторов данных)

  • get — функция, возвращающая значение свойства, либо, если она отсутствует — undefined (для дескрипторов доступа)

  • set — функция, изменяющая значение свойства, либо, если она отсутствует — undefined (для дескрипторов доступа)

  • value — значение, ассоциированное со свойством (для дескрипторов данных).

Вот пример кода:

const obj = { get es8() { return 888; } };
Object.getOwnPropertyDescriptor(obj, 'es8');
// {
//   configurable: true,
//   enumerable: true,
//   get: function es8(){}, //функция-геттер
//   set: undefined
// }

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


Поддержка браузерами (MDN)

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


Использование завершающих запятых способно упростить редактирование кода и облегчить работу с системами контроля версий. Подобная возможность уже присутствовала в языке для литералов массивов (с самого начала) и объектов (начиная с ES5). Например: [10, 20, 30,] и { x: 1, }.

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

function es8(var1, var2, var3,) {
  // ...
}

Завершающая запятая может появиться и при вызове функции:

es8(10, 20, 30,);

Асинхронные функции


Ключевое слово async позволяет определить асинхронную функцию, которая возвращает объект AsyncFunction. Внутри их работа во многом похожа на то, как работают генераторы.

Вот пример кода:

function fetchTextByPromise() {
  return new Promise(resolve => { 
    setTimeout(() => { 
      resolve("es8");
    }, 2000));
  });
}
async function sayHello() { 
  const externalFetchedText = await fetchTextByPromise();
  console.log(`Hello, ${externalFetchedText}`); // Hello, es8
}
sayHello();

Вызов sayHello() приведёт к выводу в лог строки «Hello, es8» с задержкой в 2 секунды, при этом главный поток выполнения не блокируется. Вот как это выглядит:

console.log(1);
sayHello();
console.log(2);

В консоли, после выполнения этого кода, появится следующее:

1 // немедленно
2 // немедленно
Hello, es8 // через 2 секунды

Как видно, два вызова console.log() выполняются один за другим, а асинхронная функция, не блокируя главный поток, выполняется через 2 секунды.

Обратите внимание на то, что асинхронные функции всегда возвращают промисы, и ключевое слово await можно использовать только в функциях, определённых с использованием ключевого слова async.


Поддержка браузерами (MDN)

Разделяемая память и объект Atomics


Если несколько потоков пользуются общей памятью, они могут одновременно писать в неё данные и читать данные из неё. Атомарные операции позволяют обеспечить целостность данных и предсказуемость результатов выполнения операций. То есть, например, гарантировать то, что некая операция завершится до того, как начнётся другая, или то, что некая операция не будет прервана. Подобную функциональность в ES8 обеспечивают новые механизмы языка. Во-первых — это объект SharedArrayBuffer, во-вторых, объект Atomics, содержащий набор статических методов.

Объект Atomics нельзя использовать как конструктор, он, в этом плане, похож на Math. Существуют методы объекта Atomics, которые позволяют выполнять различные безопасные операции с элементами типизированных массивов, служащих для доступа к объектам SharedArrayBuffer. Среди них, например, метод Atomics.add() для прибавления указанного числа к тому, что хранится в заданной позиции массива. Есть в Atomics и методы для организации управления блокировками, в частности, это Atomics.wait() и Atomics.wake().


Поддержка браузерами (MDN)

Заглянем в будущее: расширение возможностей тегированных шаблонных строк в ES9


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

const esth = 8;
helper`ES ${esth} is `;
function helper(strs, ...keys) {
  const str1 = strs[0]; // ES
  const str2 = strs[1]; // is
  let additionalPart = '';
  if (keys[0] == 8) { // 8
    additionalPart = 'awesome';
  }
  else {
    additionalPart = 'good';
  }
  
  return `${str1} ${keys[0]} ${str2} ${additionalPart}.`;
}

Если в esth записано число 8, функция возвратит «ES 8 is awesome». Если же в esth будет 7, то функция вернёт «ES 7 is good».

Однако, до сих пор на тегированные шаблоны накладываются некоторые ограничения. Они связаны с escape-последовательностями. Например, это касается подстрок, начинающихся на \u или \x. В частности, например, после \u должен следовать код символа Unicode, иначе появится сообщение об ошибке. Ожидается, что в ES9 это ограничение будет снято.


Поддержка браузерами (MDN)

Итоги


JavaScript — это язык, который используется в неисчислимом множестве работающих веб-проектов, и он, при этом, постоянно обновляется. Процесс этот отлично организованный и сбалансированный. На последней стадии принятия новшеств, их одобряет комитет TC39, после чего их реализуют разработчики JS-движков. Надо сказать, что большинство нововведений ES8 уже поддерживает TypeScript, их поддерживают многие браузеры, в некоторых случаях помогают полифиллы, поэтому новые возможности JavaScript можно пустить в дело прямо сейчас.

Уважаемые читатели! Пользуетесь ли вы новшествами ES8?