Что и как в ES6: хитрости, лучшие практики и примеры. Часть вторая. Мэпы, слабые мэпы, обещания, генераторы, async / await, геттеры / сеттеры, символы
22К открытий22К показов
Продолжение шпаргалки для повседневного использования по ES2015 [ES6] с примерами. Делитесь своими советами в комментариях!
Мэпы
Мэпы — это очень полезная структура данных. До ES6 хеш-мэпы создавались через объекты:
Однако это не защищает от случайной перегрузки функций с конкретными именами свойств:
Настоящие мэпы позволяют устанавливать значения (set
), брать их (get
), искать их (search
) и многое другое.
Самое замечательное — это то, что теперь мы не обязаны использовать только строки. Можно использовать любой тип как ключ, и он не будет приведён к строковому виду.
Примечание: использование сложных величин (функций, объектов) невозможно при проверке на равенство при использовании методов наподобие map.get(). Поэтому используйте простые величины: строки, логические переменные и числа.
Также по мэпам можно итерироваться через .entries()
:
Слабые мэпы
В версиях младше ES6 было несколько способов хранения приватных данных. Например, можно было использовать соглашения по именованию:
Но такие соглашения могут запутать, да и не всегда их придерживаются. Вместо этого можно использовать WeakMaps:
Фишкой WeakMaps является то, что ключи приватных данных не выдают имена свойств, которые можно увидеть, используя Reflect.ownKeys()
:
Практическим примером использования WeakMaps является хранение данных, связанных с элементом DOM, при этом сама DOM не захламляется:
Как видно выше, когда объект уничтожается сборщиком мусора, WeakMap автоматически удаляет пару ключ-значение, которая идентифицировалась этим объектом.
Обещания
Обещания, о которых мы подробно рассказывали в отдельной статье, позволяют превратить “горизонтальный” код:
В вертикальный:
До ES6, приходилось использовать bluebird или Q. Теперь Promises реализованы нативно:
У нас есть два обработчика, resolve (функция, вызываемая при выполнении обещания) и reject (функция, вызываемая при невыполнении обещания).
Преимущества Promises: обработка ошибок с кучей вложенных коллбэков — это ад. Обещания же выглядят гораздо приятнее. Кроме того, значение обещания после его разрешения неизменно.
Вот практический пример использования Promises:
Мы также можем распараллеливать обещания для обработки массива асинхронных операций, используя Promise.all()
:
Генераторы
Подобно обещаниям, позволяющим нам избежать ада коллбэков, генераторы позволяют сгладить код, придавая асинхронному коду синхронный облик. Генераторы — это функции, которые могут приостановить своё выполнение и впоследствии вернуть значение выражения.
Простой пример использования приведён ниже:
next позволяет передать генератор дальше и вычислить новое выражение. Пример выше предельно прост, но на самом деле генераторы можно использовать для написания асинхронного кода в синхронном виде:
А вот функция-генератор, которая возвращает наши данные:
Благодаря силе yield
мы можем быть уверены, что в entry1
будут нужные данные, которые будут переданы в data1
.
Тем не менее, для обработки ошибок придётся что-то придумать. Можно использовать Promises:
И мы пишем функцию, которая будет проходить по генератору, используя next
, который в свою очередь будет использовать метод request
:
Дополняя обещанием наш генератор, мы получаем понятный способ передачи ошибок путём .catch
и reject
. При этом использовать генератор всё так же просто:
Async Await
Хотя эта функция появится только в ES2016, async await
позволяет нам делать то же самое, что и в предыдущем примере, но с меньшими усилиями:
По сути, это работает так же, как и генераторы, но использовать лучше именно эту функцию.
Геттеры и сеттеры
ES6 привнесла поддержку геттеров и сеттеров. Вот пример:
Свежие браузеры также позволяют использовать геттеры / сеттеры в объектах, и тогда их можно использовать для вычисленных свойств, добавляя слушатели перед ними:
Символы
Символы существовали и до ES6, но теперь стал доступен публичный интерфейс для их прямого использования. Символы неизменяемы и уникальны, и их можно использовать в качестве ключей любого хеша.
Symbol( )
Вызов Symbol()
или Symbol(description)
создаст уникальный символ, недоступный глобально. Symbol()
обычно используется для добавления своей логики в сторонние объекты или пространства имён, но нужно быть осторожным с дальнейшими обновлениями этих библиотек. Например, если вы хотите добавить метод refreshComponent
в класс React.Component
, убедитесь, что он не совпадёт с методом, добавленном в следующем обновлении:
Symbol.for(key)
Symbol.for(key)
создаст символ, который по-прежнему будет неизменяемым и уникальным, но доступным глобально. Два идентичных вызова Symbol.for(key)
вернут одну и ту же сущность Symbol.
Примечание: это неверно для Symbol(description):
Символы, в частности, Symbol.for(key)
, обычно используют для интероперабельности, производя поиск символьного поля в аргументах стороннего объекта с известным интерфейсом, например:
А в другой библиотеке:
В качестве примера использования символов для интероперабельности стоит отметить Symbol.iterator, существующий во всех итерируемых типах ES6: массивах, строках, генераторах и т.д. При запуске метода возвращается объект с интерфейсом итератора.
Кстати, познакомиться с примерами использования всех новых возможностей можно, пройдя обучающий видеокурс по JavaScript, о котором мы писали ранее.
22К открытий22К показов