Правильный способ внедрить чистый класс в приложение angular 1.x в ES6

Коллега утверждает, что это неправильный способ внедрить чистый класс JavaScript ES6 в Angular. Мне любопытно, есть ли способ лучше (более правильный)?

Кроме того, лучше ли (и почему лучше) прикреплять внедряемые зависимости (в этом примере $timeout) к экземпляру; например, this._$timeout = $timeout в конструкторе. Я лично думаю, что в этом случае нет никакого преимущества в этом.

class.factory.js

let ClassFactory = function($timeout) {
    // Factory function that simply returns class constructor.

    class MyClass {
        constructor(a, b) {
            // contrived class
            this.a = a;
            this.b = b;
            this.c = null;
        }

        applyChange() {
            // contrived class method
            const SELF = this;

            $timeout(() => {
                SELF.c = SELF.a + SELF.b;
            });
        }
    }

    return MyClass ;
};

ClassFactory.$inject = ['$timeout'];

export default ClassFactory;

app.module.js

import ClassFactory from './factories/class.factory';
import AppService from './services/app.service';


export default angular.module('myApp', [])
    .factory('ClassFactory', ClassFactory)
    .service('AppService', AppService);

Позже в другом месте мы можем использовать класс в какой-нибудь службе или контроллере для создания новых экземпляров MyClass.

app.service.js

class AppService {
    // contrived usage of our dependency injected pure class.

    constructor(ClassFactory) {
        this.array = [];
        this._ClassFactory = ClassFactory;
    }

    initialize(a, b) {
        // We can instantiate as many "MyClass" objects as we need.
        let myClass = new this._ClassFactory(a, b);

        this.array.push(myClass);
    }

    static serviceFactory(...injected) {
        AppService.instance = new AppService(...injected);
        return AppService.instance;
    }
}

AppService.serviceFactory.$inject = ['ClassFactory'];

export default AppService.serviceFactory;

person James    schedule 13.06.2017    source источник
comment
Выполнение таких действий, как AppService.instance = new AppService, также не рекомендуется. Скорее всего, он будет работать, как и ожидалось, потому что есть только 1 экземпляр приложения, а служба — это синглтон. Но это вызовет утечку памяти во время тестирования.   -  person Estus Flask    schedule 13.06.2017


Ответы (1)


На данный момент не имеет значения, является ли $timeout свойством класса или просто локальной переменной.

Обертка класса фабричной функцией не очень хорошо работает с ES6-разработкой, ее невозможно экспортировать и расширять. Тот факт, что нужна фабрика, вероятно, указывает на проблемы с дизайном.

Подобный класс может получать зависимости посредством внедрения зависимостей (в здравом смысле). Это обычная вещь, когда предполагается, что конструктор класса вызывается также с аргументами, не зависящими от зависимости:

export class MyClass {
  constructor($timeout, a, b) {
    this._$timeout = $timeout;
    ...
  }
}
...
obj = new MyClass($timeout, a, b);

Если существует более одной зависимости, вместо всех зависимостей может быть указана зависимость $injector:

export class MyClass {
  constructor($injector, a, b) {
    this._$timeout = $injector.get('$timeout');
    ...
  }
}
...
obj = new MyClass($injector, a, b);

Также может быть проблема проектирования, которая вызывает зависимость от $timeout, и, решив ее, можно избежать зависимости. Из приведенного выше кода непонятно, почему MyClass должен запускать дайджест с $timeout, его логика не содержит ничего, что требовало бы этого. За это отвечает код, который использует экземпляр MyClass и привязывает его к представлению или чему-то еще, для чего существует дайджест.

person Estus Flask    schedule 13.06.2017
comment
Это надуманный пример. Но в реальном классе нам нужен доступ к некоторым функциям Angular. Реальное использование для $timeout состоит в том, чтобы запустить цикл дайджеста Angular (в узких условиях), чтобы изменения в экземпляре класса распространялись. - person James; 13.06.2017
comment
Можете ли вы привести пример использования $injector в нашем примере? И к другим вашим комментариям: я не нашел хороших ресурсов, объясняющих, как использовать чистые классы ES6 с Angular. Использование фабрики для возврата класса было самым близким, что я мог найти. - person James; 13.06.2017
comment
@TechMedicNYC Добавлено. Да, это довольно низкопрофильный корпус, не то, что обычно обсуждается в гайдах. Фабричная функция — это то, как это было бы сделано в немодульном ES5, но это выглядит недостаточно хорошо для ES6. - person Estus Flask; 13.06.2017