Injeção de dependência via propriedades de função JavaScript





Um método conhecido, mas não muito popular, de injeção de dependência. Uma tentativa de implementar este método em pacotes DI npm populares. Outro DI.



Algumas palavras sobre OOP e DI



. . ES js .



. 2006 , — PERL. . OO , , PERL , 1, 2, .

2 , , , . , . . , .



JavaScript, , . , , .



TypeScript , , - ( ). .



, JS , . JQuery UI Widget Factory. , - , . ES6 classes ES5 . ES6 DI.



(dependency injection) . , , . , DI, .



DI . , — . , (/ , , , , ...). / . , “”, - . — ! DI.



DI — .





— , . Javascript . . , .



.



App ,



Storage — ( singleton/service),



Date, ( ).



- . (transient) “new”.



- (singleton) “one”.





class App {

    /** @type { function( int ):IDate } */
    newDate;

    /** @type { function(): IStorage } */
    oneStorage;

    construct( newDate, oneStorage ) {
        this.newDate = newDate;
        this.oneStorage = oneStorage;
    }

    main() {
        const oDate1 = this.newDate( 0 );
        const oDate2 = this.newDate( 1000 );
        const oStorage = this.oneStorage();
        oStorage.insert( oDate1.format() + ' - ' + oDate2.format() );
    }
}


, . (lazy). , ( inversify: to, toSelf, toConstantValue, toDynamicValue, toConstructor, toFactory, toFunction, toAutoFactory, toProvider, toService), DI . , .



DI . DI , , . DI .





dependency injection



, , , . dependency injection. :



  1. , . .
  2. , / . , , .
  3. , . , , , , / IDE.


DI. , DI , .



DI . , . , , DI .



, , , , , . , - , - , . . — “-” )





dependency injection javascript/typescript



, “di” npm. ~1400. . npm dependents.





repo npm dependents npm weekly downloads github stars , , lang ES classes interfaces inject property bundle size, KB open github issues github forks
inversify/Inversifyjs

1798

408k 6.6k 6 1 TS + + + 63.3 204 458
typestack/typedi 353 62k 1.9k 5 3 TS + + + 30.3 17 98
thlorenz/proxyquire 344 426k 2.6k 8 8 ES5 ? ? ? ? 9 116
jeffijoe/awilix 244 42k 1.7k 5 1 TS + - - 31.7 2 92
aurelia/dependency-injection

153

13k 156 6 2 TS + - ? ? 2 68
stampit-org/stampit 170

22k 3k 8 1 ES5 ? ? ? ? 6 107
microsoft/tsyringe

149

80k 1.5k 3 1 TS + + - 30.4 27 69
boblauer/mock-require

136 160k 441 6 1 ES5 ? ? ? ? 4 29
mgechev/injection-js 105 236k 928 4 1 TS + -? ? 41.7 0 48
young-steveo/bottlejs

101

16k 1.2k 6 1 ES5 + D.TS -? - - 13.3 2 63
jaredhanson/electrolyte

33 1k 569 7 1 ES5 - - - ? 25 65
zhang740/power-di

10

0.2k 65 4 1 TS + + + 45.0 2 69
jpex-js/vue-inject

9 0.8k 174 4 12 ES5 - - ? ? 3 14
zazoomauro/node-dependency-injection

5

1k 123 4 2 ES6 + D.TS + -? + 291.0 3 17
justmoon/constitute 4 8k 132 5 60 ES6 + -? - 56.2 4 6
owja/ioc 1

2k 158 1 3 TS + + + 11.3 4 5
kraut-dps/di-box

1 0k 0 0 1 ES6 + D.TS + + + 11.1 0 0




Gitcompare



Codesandbox





https://github.com/inversify/InversifyJS



, , , . )). , . )





https://github.com/typestack/typedi



, , . , , App Date, . , ?





https://github.com/thlorenz/proxyquire



, . . DI, .





https://github.com/jeffijoe/awilix



, “Symbol(Symbol.toPrimitive)”, , - Proxy, Date . .





https://github.com/aurelia/dependency-injection



. Aurelia.





https://github.com/stampit-org/stampit



. . - .





https://github.com/microsoft/tsyringe



Microsoft, . , .





https://github.com/boblauer/mock-require



proxyquire.





https://github.com/mgechev/injection-js



Angular 4. , , useFactory .





https://github.com/young-steveo/bottlejs



. .instanceFactory, .





https://github.com/jaredhanson/electrolyte



. ES6 .





https://github.com/zhang740/power-di



. React. . - . , .





https://github.com/jpex-js/vue-inject



vue ES6 . . ES6 classes, provide inject DI. .





https://github.com/zazoomauro/node-dependency-injection



YAML/JS/JSON . . php symfony , setParameter, , .





https://github.com/justmoon/constitute



, , DI .





https://github.com/owja/ioc



inversify, . , : , , . , .





https://github.com/kraut-dps/di-box



, .





, , DI , , .







“”, :





class Service {
    work () {
        console.log('work');
    }
}

class App {
    oneService;
    main () {
        this.oneService().work();
    }
}

//  es6 ,   DI
class AppBox {
    Service;
    App;

    _oService;

    newApp () {
        const oApp = new this.App();

        //   
        oApp.oneService = this.oneService.bind(this);

        return oApp;
    }

    oneService () {
        if (!this._oService) {
            this._oService = new this.Service();
        }
        return this._oService;
    }
}

const oBox = new AppBox();
oBox.Service = Service;
oBox.App = App;
const oApp = oBox.newApp();
oApp.main();


Box , , .

(.one()), bind(this), . :





import {Box} from "di-box";

class Service {
    work() {
        console.log( 'work' );
    }
}

class App {
    oneService;
    main() {
        this.oneService().work();
    }
}

class AppBox extends Box {
    App;
    Service;

    newService() {
        return new this.Service();
    }

    oneService() {
        return this.one( this.newService );
    }

    newApp() {
        const oApp = new this.App();
        oApp.oneService = this.oneService;
        return oApp;
    }
}

const oBox = new AppBox();
oBox.Service = Service;
oBox.App = App;
const oApp = oBox.newApp();
oApp.main();


codesandbox





:



const oBox = new AppBox();
//  oBox.Service = Service;
oBox.App = App;
const oApp = oBox.newApp(); //   :  Service is undefined
oApp.main();


...



DI . , , . , .

:





constructor( arg1, arg2, arg3 ) {}

// 

constructor( { arg1key: arg1, arg2key: arg2, arg3key: arg3 } ) {}


, . ?



  1. - .
  2. .


ES . , - . DI .



. undefined. . .



:





class A {
    _arg1;
    _arg2;

    constructor( arg1, arg2 = null ) {
        this._arg1 = arg1;
        this._arg2 = arg2;
    }
}
const instance = new A( 1, 2 );

// 

class A {
    arg1; //  ,   
    arg2 = null; //    null !== undefined
}
const instance = new A();
instance.arg1 = 1;
instance.arg2 = 2;


dependency injection , . di-box.

typescript constructor( public arg1: type, public arg2: type ) Box:



new AppBox( { bNeedSelfCheck: false, sNeedCheckPrefix: null } );


codesandbox.



Portanto, com o di-box, temos a oportunidade de escrever no estilo OOP, com código adicional mínimo, mas suficiente, que implementa DI. Por um lado, há uma "mágica" prototípica na implementação, mas, por outro lado, ela ocorre apenas no nível meta, e os próprios componentes podem ser puros e não saber nada sobre o ambiente.



Eu ficaria feliz em discutir isso, talvez eu tenha perdido algumas outras bibliotecas. Ou talvez você saiba a melhor forma de implementar meu exemplo em algumas das implementações de DI. Escreva nos comentários.




All Articles