【翻译】InversifyJS 中文文档

和网友 Jeff-Tian 一块儿翻译了 InversifyJS 英文文档, ღ( ´・ᴗ・` )比心html

仓库地址:github.com/NeoYo/inver… 欢迎 fork or startnode

InversifyJS一个强大又轻量的控制反转容器,提供给JavaScript 和 Node.js 应用使用,使用TypeScript编写。git

InversifyJS 地址:github.com/inversify/I…es6

InversifyJS官网:inversify.iogithub

InversifyJS中文文档:www.inversify.cnnpm

简介

InversifyJS 是一个轻量的 (4KB) 控制反转容器 (IoC),可用于编写 TypeScript 和 JavaScript 应用。 它使用类构造函数去定义和注入它的依赖。InversifyJS API 很友好易懂, 鼓励对 OOP 和 IoC 最佳实践的应用.编程

为何要有 InversifyJS?

JavaScript 如今支持面向对象编程,基于类的继承。 这些特性不错但事实上它们也是 危险的。 咱们须要一个优秀的面向对象设计(好比 SOLIDComposite Reuse等)来保护咱们避免这些威胁。然而,面向对象的设计是复杂的,因此咱们建立了 InversifyJS。json

InversifyJS 是一个工具,它能帮助 JavaScript 开发者,写出出色的面向对象设计的代码。api

目标

InversifyJS有4个主要目标:markdown

  1. 容许JavaScript开发人员编写遵循 SOLID 原则的代码。

  2. 促进并鼓励遵照最佳的面向对象编程和依赖注入实践。

  3. 尽量少的运行时开销。

  4. 提供艺术编程体验和生态

业内评价

Nate Kohari - Ninject的做者

"Nice work! I've taken a couple shots at creating DI frameworks for JavaScript and TypeScript, but the lack of RTTI really hinders things.The ES7 metadata gets us part of the way there (as you've discovered). Keep up the great work!"

Michel Weststrate - MobX的做者

Dependency injection like InversifyJS works nicely

使用 InversifyJS 的公司

image.png

安装

您能够使用npm得到最新的版本和类型定义:

$ npm install inversify reflect-metadata --save
复制代码

Inversify npm 包已经包含了 InversifyJS 的类型定义

:警示: 重要! InversifyJS 须要 TypeScript 的版本 >= 2.0 还有 experimentalDecorators, emitDecoratorMetadata, types and libtsconfig.json 中 compilerOptions 的配置以下:

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["es6"],
        "types": ["reflect-metadata"],
        "module": "commonjs",
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}
复制代码

inversifyjs须要现代JavaScript引擎,支持如下特性

若是您的运行环境不支持这些特性,您可能须要导入 shimpolyfill

:警示: reflect-metadata polyfill 应该在您整个应用中只导入一次 由于 Reflect 对象须要成为一个全局的单例。 更多细节能够在这里找到。

查看维基中的开发环境 polyfills , 还能够从基本示例中去学习.

基础部分

让咱们一块儿看下 inversifyjs 的基本用法和 API:

步骤 1: 声明接口和类型

咱们的目标是编写遵循依赖倒置原则的代码。

这意味着咱们应该 ”依赖于抽象而不依赖于具体实现“ 。

让咱们先声明一些接口(抽象)。

// file interfaces.ts

interface Warrior {
    fight(): string;
    sneak(): string;
}

interface Weapon {
    hit(): string;
}

interface ThrowableWeapon {
    throw(): string;
}
复制代码

Inversifyjs 须要在运行时使用类型标记做为标识符。接下来将使用 Symbol 做为标识符,您也可使用类或字符串。

// file types.ts

const TYPES = {
    Warrior: Symbol.for("Warrior"),
    Weapon: Symbol.for("Weapon"),
    ThrowableWeapon: Symbol.for("ThrowableWeapon")
};

export { TYPES };

复制代码

警示: 推荐使用 Symbol,但 InversifyJS 也支持使用类和字符串字面值 (请查阅特性部分了解更多)。

步骤 2: 使用 @injectable@inject 装饰器声明依赖

让咱们来声明一些类,实现刚刚声明接口。他们都须要使用 @injectable 装饰器去注解。

当一个类依赖于某个接口时,咱们也须要使用 @inject 装饰器,来定义在运行时可用的接口标识。在这种状况下,咱们将使用 Symbol, 如 Symbol.for("Weapon")Symbol.for("ThrowableWeapon") 做为运行时的标识。

// file entities.ts

import { injectable, inject } from "inversify";
import "reflect-metadata";
import { Weapon, ThrowableWeapon, Warrior } from "./interfaces"
import { TYPES } from "./types";

@injectable()
class Katana implements Weapon {
    public hit() {
        return "cut!";
    }
}

@injectable()
class Shuriken implements ThrowableWeapon {
    public throw() {
        return "hit!";
    }
}

@injectable()
class Ninja implements Warrior {

    private _katana: Weapon;
    private _shuriken: ThrowableWeapon;

    public constructor( @inject(TYPES.Weapon) katana: Weapon, @inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon ) {
        this._katana = katana;
        this._shuriken = shuriken;
    }

    public fight() { return this._katana.hit(); }
    public sneak() { return this._shuriken.throw(); }

}

export { Ninja, Katana, Shuriken };
复制代码

若是您更喜欢使用属性注入而不是构造函数注入,那就能够不用声明类的构造函数了:

@injectable()
class Ninja implements Warrior {
    @inject(TYPES.Weapon) private _katana: Weapon;
    @inject(TYPES.ThrowableWeapon) private _shuriken: ThrowableWeapon;
    public fight() { return this._katana.hit(); }
    public sneak() { return this._shuriken.throw(); }
}
复制代码

步骤 3: 建立和配置容器

推荐在命名为 inversify.config.ts 的文件中建立和配置容器。这是惟一有耦合的地方。 在您项目其他部分中的类,不该该包含对其余类的引用。

// file inversify.config.ts

import { Container } from "inversify";
import { TYPES } from "./types";
import { Warrior, Weapon, ThrowableWeapon } from "./interfaces";
import { Ninja, Katana, Shuriken } from "./entities";

const myContainer = new Container();
myContainer.bind<Warrior>(TYPES.Warrior).to(Ninja);
myContainer.bind<Weapon>(TYPES.Weapon).to(Katana);
myContainer.bind<ThrowableWeapon>(TYPES.ThrowableWeapon).to(Shuriken);

export { myContainer };
复制代码

步骤 4: 解析依赖

您可使用方法 get<T>Container 中得到依赖。记得您应该在根结构(尽量靠近应用程序的入口点的位置)去解析依赖,避免服务器定位反模式

import { myContainer } from "./inversify.config";
import { TYPES } from "./types";
import { Warrior } from "./interfaces";

const ninja = myContainer.get<Warrior>(TYPES.Warrior);

expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true
复制代码

正如咱们所看到的 Katana and Shuriken 被成功的解析和注入进 Ninja

InversifyJS 支持 ES5 和 ES6 并且能够在没有 TypeScript 环境下使用。 前往 JavaScript 示例了解更多

InversifyJS 特性 和 API

让咱们一块儿看看 InversifyJS 的特性!

请查阅 wiki 获取更多细节。

请查阅 wiki 获取更多细节。

生态

为了提供艺术般的开发体验,咱们也不断努力:

请查阅 生态 wiki 页 去了解更多。

Support

若是您遇到任何问题,咱们乐意帮忙。您可使用 问题页 报告问题。

若是您想要和开发团队分享您的想法或者加入咱们,您能够参加 论坛讨论。您也能够查看 wiki 来了解更多关于 InversifyJS。

Acknowledgements

Thanks a lot to all the contributors, all the developers out there using InversifyJS and all those that help us to spread the word by sharing content about InversifyJS online. Without your feedback and support this project would not be possible.

License

License under the MIT License (MIT)

Copyright © 2015-2017 Remo H. Jansen

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.