С введением классов ES6 некоторые конструкции Angular стали более разборчивыми. В этом посте я расскажу, где их использовать, преобразую контроллер на основе функций в класс ES6, чтобы показать ясность, и расскажу, когда их не использовать.
Прежде чем читать, пожалуйста, обратитесь к моему сообщению о классах ES6 и когда их использовать.
Созданные объекты
Существует несколько типов конструкций Angular, которые создаются во время жизненного цикла Angular путем вызова new
для аргумента, представляющего конструкцию. К ним относятся controller
и service
. Когда Angular создает эти объекты для использования $injector
, он создает экземпляры объектов. Службы будут созданы один раз в течение жизненного цикла Angular (когда они впервые понадобятся какой-либо конструкции). С этого момента возвращаемая ссылка вводится в каждую конструкцию. Это делает его идеальным способом передачи данных по всему приложению.
Контроллеры создаются для каждого использования (для компонентов, директив, маршрутов и т. д.). Они поддерживают состояние этих отдельных видов использования.
Некоторыми примерами конструкций Angular без создания экземпляров являются фильтры, директивы и фабрики. Они просто называются функциями и плохо служат в качестве классов. Это можно обойти, предоставив анонимную функцию, которая сообщает об экземпляре класса. Придется также передавать все введенные аргументы из анонимной функции в класс, что усложнит обслуживание!
Преимущества службы/контроллера Angular как класса
Моей основной причиной использования классов является удобство чтения. Обозначение функций подходит, если разработчики привыкли к Javascript и понимают проблемы, к которым может привести использование ключевого слова this
в кодовой базе. Однако это приводит к тому, что я считаю плохой практикой.
Разработчик с меньшей вероятностью объявит вещи разумным образом. Когда все присваивается переменной this
(функции и значения), она имеет тенденцию смешивать значения и объявления функций, где нелегко понять, где что-то определяется. Это становится особенно верным, когда функция расширяется.
В классах значения не могут быть определены вне функций.
Кроме того, он также выделяет функции определенного класса из-за нотации.
Недостатки
Есть только один недостаток, на который я жалуюсь. В конструкторе переданные параметры должны быть явно назначены экземпляру и упомянуты в других функциях с помощью this.parameter
. Я не возражаю против поведения, если разработчики поддерживают введенное имя (например, MyService назначается экземпляру контроллера путем установки this.MyService = MyService
.
Typescript прекрасно справляется с этим, автоматически назначая параметры экземпляру класса, если он определен как общедоступный/частный и т. д., но это совсем другая история.
Пример
function MyController($filter, MyService) {
this.format = 'short';
this.updateDatabase = (viewData) => {
MyService.updateDatabase(viewData);
};
this.$onInit = () => {
this.dateValue = $filter.get('date')(this.date, this.format);
});
}
Вышеизложенное зависит от понимания разработчиком стрелочных функций. Если разработчик решил использовать function
, то ему пришлось бы ссылаться на экземпляр контроллера с помощью псевдонима ссылки на this
.
Приведенное выше также является значительно упрощенным примером… но здесь это как класс:
class MyController {
constructor($filter, MyService) {
const format = 'short';
Object.assign(this, {
$filter, MyService, format
});
}
$onInit() {
this.dateValue = this.$filter.get('date')(this.date, this.format);
}
updateDatabase(viewData) {
this.MyService.updateDatabase(viewData);
}
}
Есть некоторые дополнительные шаблоны, связанные с конструктором и вызывающими зависимостями, которые предоставляются в конструкторе. Однако в последнем есть некоторая польза. То есть легко указать, откуда взялось значение. Он был назначен где-то экземпляру контроллера, который можно проследить до конструктора.
Некоторые рекомендации по использованию классов
- Конструкторы предназначены для установки констант и внедрения объектов в контроллер, и ничего больше. Это обеспечивает правильную инициализацию значений из привязок и служб и т.п.
- Используйте $onInit для контроллеров для любой дополнительной настройки необходимых значений, которые рассчитываются (на основе привязок, значений, переданных конструктору и т. д.).
- Поднимите крючки жизненного цикла Angular наверх. К ним относятся
$onInit
,$onChanges
,$onDestroy
и$postLink
. Это выделит поведение контроллера, специфичное для Angular. Кроме того, он перемещает вспомогательные функции и просмотр взаимодействий вниз. - Используйте
Object.assign
, чтобы очистить нотацию конструктора, используя сокращенное определение объекта (где имя свойства и переменной совпадают).
Вывод
За три года работы с Angular я полюбил нотацию классов там, где это уместно в приложении. Это сокращает часть многословия объявления функций, а также запутывает поведение ключевого слова this
, что полезно для менее опытных разработчиков.