Сегодняшняя повестка дня:

  • Декораторы
  • Декораторы
  • И декораторы

Пропускаемое вступление о личной жизни автора

Я должен признать, что это особенная запись в блоге для меня. Меня всегда интересовали декораторы в Javascript, так как я впервые о них услышал. Правда, это было всего 3 месяца назад, но все же…

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

Я знаю, о чем вы думаете, и я тоже так думал в то время. Это определенно была черная магия в действии.

Но нет, туториалы устарели до чертиков, а декораторы за это время изменились, а туториалов не последовало за развитием. Я знаю… Странно!

Итак, я подумал: если другие могут делать учебники, которые со временем устаревают, то, черт возьми, я тоже могу!

Итак, давайте сделаем это!

Декораторы

Если вы не знаете, что такое декораторы, то это просто функция, которую мы используем, чтобы «украсить» класс или член класса, чтобы расширить его поведение. Они берут дескриптор объекта, вызывающего декоратор (это может быть класс, метод или поле), и, изменяя этот дескриптор, мы можем делать некоторые изящные вещи, как мы увидим ниже.

Вот некоторый материал для вас, чтобы, по крайней мере, получить общее представление о дескрипторах.







Вот плагин babel, который позволяет нам использовать декораторы:



Кроме того, для этого урока нам нужно включить decoratorsBeforeExport из плагина. Вы можете увидеть, как это делается по приведенному выше URL-адресу на странице Babel.

Пример декоратора клише

Я не могу, конечно, показать вам потрясающие вещи, которые мы можем делать с декораторами, прежде чем показать вам сначала простой пример, не так ли? Если школа меня чему-то и научила, так это тому, что я не могу.

Давайте начнем с предотвращения переназначения поля класса другому значению, добавив наш собственный декоратор «только для чтения».

Начнем с этого класса:

Если мы «console.log» эту переменную, мы, очевидно, можем увидеть напечатанное значение:

И вот приходит супер-хакер и делает это:

Ой…

Теперь мы можем сделать эту переменную доступной только для чтения, перезаписав дескриптор поля «Object.defineProperty», как вы можете видеть здесь:

https://developer.mozilla.org/pt-PT/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Но мы можем сделать это более элегантно с помощью декораторов, так что давайте сделаем это.

Как я сказал выше, декораторы — это просто функции, поэтому давайте реализуем функцию только для чтения.

Этот параметр дескриптора представляет собой объект, описывающий поле класса:

У вас есть описание большинства этих полей в приведенном выше URL-адресе в категории «Декораторы» (первый из трех URL-адресов).

Мы знаем, что для того, чтобы сделать поле доступным только для чтения, нам нужно изменить свойство «доступно для записи» на «false» и вернуть «новый» дескриптор в реализации декоратора, который будет выглядеть примерно так:

Теперь, когда супер крутой хакер снова попытается изменить переменную, он встретится с нашим супер классным брандмауэром:

Мат хакер человек. Мат.

Мы также можем передавать параметры нашим декораторам, и в этом случае декоратор будет функцией, принимающей переданные нами параметры и возвращающей обычную функцию с дескриптором в качестве параметра. Что-то вроде этого:

Сочная часть учебника. Полезные и практические примеры

Чтобы понять следующую часть, нам нужно знать о существовании поля дескриптора «finisher».

По предложению:

finisher — это обратный вызов, который вызывается в конце создания класса. Это необязательно.

Это полезно, если нам нужно получить фактический класс, оформленный декоратором, а не дескриптор класса. Давайте посмотрим на примере:

Функция Redux Connect

Функция redux connect часто используется следующим образом:

Этот параметр компонента является фактическим классом, который вызывает декоратор, и теперь мы знаем, что можем получить его с помощью обратного вызова «finisher» следующим образом:

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

Теперь мы можем просто вызвать его так:

Это довольно круто, если я сам так говорю. И я делаю.

Тем не менее, это не сильно отличается от обычного вызова «connect», верно?

Хорошо, я дам тебе это. Это в значительной степени просто синтаксический сахар, так что давайте посмотрим больше примеров.

Профилирование времени метода

Давайте создадим декоратор, который сообщает нам, сколько времени потребовалось для выполнения метода класса от начала до конца. Звучит довольно круто, верно? Я знаю!

Этот класс имеет статический метод, который просто спит в течение 5 секунд, имитируя длинную задачу.

Мне нужен способ узнать, что этот метод на самом деле занял 5 секунд.

Мы можем сделать это так:

И это работает:

Но это скучно, мы должны делать это в каждом методе, который хотим профилировать? Добавить целых две строки?? Что, если нам придется изменить способ профилирования? Может быть, немного изменить имя таймера в каждом таймере? Буу!

Так что давайте украшать этот метод сложнее, чем елку!

Мы знаем, что для работы декоратора нам нужно выполнить «console.time» до выполнения метода и «console.timeEnd» после.

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

Это «descriptor.value» — это то, что нам нужно. Это актуальный метод. У меня появляются гадкие мысли. Давай перезапишем!

Мы уже знаем, как работает этот декоратор, поэтому все, что я собираюсь объяснить, это то, что мы перезаписываем исходный метод нашим новым методом, окруженным «console.time» и «console.timeEnd».

Теперь, когда мы используем декоратор в методе, мы получаем точно такой же результат:

Посмотрите, как красиво! 😍

Я знаю, о чем вы думаете: «Мууууууууууууууууу!».

Ты получил это!

с маршрутизатором

«withRouter» является частью пакета «react-router», и он полезен, когда нам нужно знать информацию внутри компонента о том, «где» мы находимся. Мы можем использовать это, чтобы увидеть, установлен ли в настоящее время определенный параметр запроса в URL-адресе, нашем текущем местоположении страницы и т. д.

Он используется следующим образом:

Пфф! Но это по-старому! Мы фронтенд-разработчики, мы постоянно ищем разные, возможно, лучшие способы делать одни и те же вещи! В этом его привлекательность.

Итак, давайте создадим для него декоратор:

Это очень похоже на декоратор connect. Это просто для того, чтобы продемонстрировать, как легко реализовать определенные функции, которые мы постоянно пишем в процессе разработки.

Мы просто добавляем декоратор (кстати, мы можем сцепить декораторы), и все готово!

У нас есть доступ к свойствам местоположения, предоставленным нам «withRouter». Прохладный!

Компонент Route JSX React-Router

Это распространенный пример маршрутизации в React:

Но если бы мы хотели, чтобы реальная логика рендеринга находилась в компоненте «TestRoute», а не в родительском компоненте, мы могли бы добавить декоратор. Нравится:

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

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

Кроме того, если бы вы могли аплодировать или подписаться, это было бы здорово, так что я могу без зазрения совести указать это в своем резюме и LinkedIn.

Цитата недели

«Если грубая сила не решает ваших проблем, значит, вы недостаточно ее используете».

Неизвестный

Увидимся на следующей неделе! 👌