Skip to content

Latest commit

 

History

History
242 lines (122 loc) · 31.6 KB

File metadata and controls

242 lines (122 loc) · 31.6 KB

ECMAScript

Описание

ECMAScript — это встраиваемый расширяемый не имеющий средств ввода-вывода язык программирования, используемый в качестве основы для построения других скриптовых языков. Стандартизирован международной организацией ECMA в спецификации ECMA-262.

JavaScript создавался как скриптовый язык для Netscape. После чего он был отправлен в ECMA International для стандартизации (ECMA — это ассоциация, деятельность которой посвящена стандартизации информационных и коммуникационных технологий). Это привело к появлению нового языкового стандарта, известного как ECMAScript.

Последующие версии JavaScript уже были основаны на стандарте ECMAScript. Проще говоря, ECMAScript — стандарт, а JavaScript — самая популярная реализация этого стандарта.

ES2015 / ES6

let, const и блочная область видимости

Ключевое слово let позволяет объявлять переменные с ограниченной областью видимости — только для блока {...}, в котором происходит объявление. Это называется блочной областью видимости. Вместо ключевого слова var, которое обеспечивает область видимости внутри функции, стандарт ES6 рекомендует использовать let.

Другой формой объявления переменной с блочной областью видимости является ключевое слово const. Оно предназначено для объявления переменных (констант), значения которых доступны только для чтения. Это означает не то, что значение константы неизменно, а то, что идентификатор переменной не может быть переприсвоен.

Стрелочные функции

Стрелочные функции представляют собой сокращенную запись функций в ES6. Стрелочная функция состоит из списка параметров ( ... ), за которым следует знак => и тело функции.

Стрелочные функции не просто делают код короче. Они тесно связаны с ключевым словом this и привязкой контекста. Поведение стрелочных функций с ключевым словом this отличается от поведения обычных функций с this. Каждая функция в JavaScript определяет свой собственный контекст this, но внутри стрелочных функций значение this то же самое, что и снаружи (стрелочные функции не имеют своего this).

Параметры по умолчанию

ES6 позволяет установить параметры по умолчанию при объявлении функции.

Spread / Rest оператор

... оператор называют как spread или rest, в зависимости от того, как и где он используется.

При использовании в любом итерируемом объекте (iterable), данный оператор "разбивает" ("spread") его на индивидуальные элементы. Другим распространенным использованием оператора ... является объединение набора значений в один массив. В данном случае оператор работает как "rest".

Расширение возможностей литералов объекта

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

Восьмеричный и двоичный литералы

В ES6 появилась новая поддержка для восьмеричных и двоичных литералов. Добавление к началу числа 0o или 0O преобразует его в восьмеричную систему счисления (аналогично, 0b или 0B преобразует в двоичную систему счисления).

Деструктуризация массивов и объектов

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

Ключевое слово super для объектов

ES6 позволяет использовать метод super в (безклассовых) объектах с прототипами.

Строковые шаблоны и разделители

ES6 предоставяляет более простой способ вставки значения переменной или результата выражения (т.н. "интерполяцию"), которые рассчитываются автоматически.

  • ${ ... } используется для вычисления значения переменной/выражения
  • `` Обратные кавычки используются как разделитель для таких случаев

for...of против for...in

for...of используется для перебора в цикле итерируемых объектов, например, массивов. for...in же используется для перебора в цикле всех доступных для перебора (enumerable) свойств объекта.

Map и WeakMap

ES6 представляет новые структуры данных — Map и WeakMap. На самом деле, мы используем "Map" в JavaScript все время. Каждый объект можно представить как частный случай Map.

Классический объект состоит из ключей (всегда в строковом виде) и значений, тогда как в Map для ключа и значения можно использовать любое значение (и объекты, и примитивы).

WeakMap это Map, в котором ключи обладают неустойчивыми связями, что позволяет не мешать сборщику мусора удалять элементы WeakMap. Это означает, что можно не беспокоиться об утечках памяти. Стоить отметить, что в WeakMap, в отличие от Map, каждый ключ должен быть объектом.

Set и WeakSet

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

Аналогично WeakMap, объект WeakSet позволяет хранить объекты с неустойчивыми связями в коллекции. Объект в WeakSet уникален.

Классы

В ES6 представили новый синтаксис для классов. Здесь стоит отметить, что класс ES6 не представляет собой новую объектно-ориентированную модель наследования. Это просто синтаксический сахар для существующего в JavaScript прототипного наследования.

Класс в ES6 представляет собой просто новый синтаксис для работы с прототипами и функциями-конструкторами, которые мы привыкли использовать в ES5.

Функции, записанные с помощью ключевого слова static, используются для объявления статических свойств класса.

Тип данных Symbol

Symbol это уникальный и неизменяемый тип данных, представленный в ES6. Целью Symbol является создание уникального идентификатора, к которому нельзя получить доступ.

Если Symbol используется как свойство/ключ объекта, он сохраняется таким специальным образом, что свойство не будет показано при нормальном перечислении свойств объекта.

Итераторы

Итератор обращается к элементам коллекции по одному, в то же время сохраняя память о своей текущей позиции в этой коллекции. У итератора есть метод next(), который возвращает следующий элемент в последовательности. Этот метод возвращает объект с двумя свойствами: done (окончен ли перебор) и value (значение).

В ES6 есть метод Symbol.iterator, который определяет итератор для объекта по-умолчанию. При каждой необходимости перебора в цикле для объекта (например, в начале цикла for..of), его метод итератора вызывается без аргументов, и возвращенный итератор используется для того, чтобы получить значения для перебора.

Генераторы

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

Функция-генератор возвращает итерируемый объект при своем вызове. Функция-генератор записывается с помощью знака * после ключевого слова function, а в теле функции должно присутствовать ключевое слово yield. Каждый раз при вызове yield возвращенное значение становится следующим значением в последовательности.

Промисы

В ES6 появилась встроенная поддержка промисов. Промис это объект, который ждет выполнения асинхронной операции, после которого (т.е. после выполнения) промис принимает одно из двух состояний: fulfilled (resolved, успешное выполнение) или rejected (выполнено с ошибкой).

Стандартным способом создания промиса является конструктор new Promise(), который принимает обработчик с двумя функциями как параметрами. Первый обработчик (обычно именуемый resolve) представляет собой функцию для вызова вместе с будущим значением, когда оно будет готово; второй обработчик (обычно именуемый reject) является функцией, которая вызывается для отказа от выполнения промиса, если он не может определить будущее значение.

ES2016 / ES7

Array.prototype.includes()

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

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

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

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

ES2017 / ES8

Object.values()

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

Object.entries()

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

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

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

Object.getOwnPropertyDescriptors()

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

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

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

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

Это нововведение я назвал бы самым важным и самым полезным. Асинхронные функции позволяют избавиться от так называемого «ада коллбэков» и улучшить внешний вид и читаемость кода.

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

ES2018 / ES9

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Promise.prototype.finally()

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

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

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

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

Полезные ссылки