对我来说,Angular 的依赖注入如何改进我的项目的几个方面,我将在这里列出。我希望这将向您展示其他人如何从中受益,但是如果您是组织良好且经验丰富的 JS 开发人员,那么对您来说可能就不一样了。我认为在某些时候这只是开发自己的工具和编码指南的问题。
统一的、声明性的依赖解析
JS 是动态语言(这是新的,对吧?),它赋予了程序员很大的权力,甚至更多的责任。组件可以通过传递各种对象以各种方式相互交互:常规对象、单例、函数等。它们甚至可以使用甚至没有提到其他组件使用的代码块。
JS 从来没有(而且很可能永远不会)像其他语言(Java、C、C#)那样声明公共、私有或包(模块)范围的统一方式。当然有封装逻辑的方法,但是问任何一个语言新手,他根本不知道如何使用它。
我喜欢 DI(不仅在 Angular 中,而且在一般情况下)的一点是,您可以列出对组件的依赖项,并且您不必担心这种依赖项是如何构建的。这对我来说非常重要,尤其是 Angular 中的 DI 允许您解析两种组件:这些来自框架本身(如$http
),或自定义组件(如我最喜欢的eventBus
用于包装$on
事件处理程序的组件)。
我经常查看服务的声明,并且仅通过查看依赖关系就知道它做了什么以及它是如何做的!
如果我要在组件本身深处构建和/或使用所有这些对象,那么我总是必须彻底分析实现并从各个方面检查它。如果我localStorage
在依赖项列表中看到,我知道我正在使用 HTML5 本地存储来保存一些数据。我不必在代码中查找它。
组件的使用寿命
我们不再需要为某些组件的初始化顺序而烦恼。如果A
依赖,B
那么 DI 将确保B
在需要时准备好A
。
单元测试
当您使用 DI 时,它对模拟组件有很大帮助。例如,如果您有控制器:function Ctrl($scope, a, b, c, d)
那么您会立即知道它依赖于什么。您注入适当的模拟,并确保所有与您的控制器交谈和收听的各方都是隔离的。如果您在编写测试时遇到麻烦,那么您很可能搞砸了抽象级别或违反了设计原则(直径定律、封装等)
好习惯
是的,您很可能可以使用命名空间来正确管理对象的生命周期。在需要的地方定义单例,并确保没有人弄乱你的私人成员。但老实说,如果框架可以为您做到这一点,您是否需要它?直到我学会了 Angular,我才“以正确的方式”使用 JS。并不是我不在乎,我只是没有必要,因为我只是在几周的 UI 中使用 JS,主要基于 jquery。
现在不同了,我有一个很好的框架,它迫使我有点跟上良好的实践,但它也给了我很大的力量来扩展它并利用 JS 的最佳特性。
当然,糟糕的程序员仍然可以打破最好的工具,但是从我最近阅读 D. Crockford 的“JS 好的部分”中学到的东西,人们正在用它做令人讨厌的事情。多亏了 jQuery、Angular 等优秀的工具,我们现在有了一些很好的工具,可以帮助编写好的 JS 应用程序并在这样做的同时坚持最佳实践。
结论
正如您所指出的,您可以通过至少做以下三件事来编写好的 JS 应用程序:
- 命名空间——这避免了向全局命名空间添加东西,避免潜在的冲突,并允许在需要时轻松解析适当的组件
- 创建可重用的组件/模块 - 例如,通过使用功能模块模式并显式声明私有和公共成员
- 管理组件之间的依赖关系——通过定义单例,允许从一些“注册表”中检索依赖关系,当某些条件不满足时不允许做某些事情
Angular 只是通过以下方式做到这一点:
- 拥有
$injector
which 管理组件之间的依赖关系并在需要时检索它们
- 强制使用同时具有 PRIVATE 和 PUBLIC API 的工厂函数。
- 让组件直接(通过相互依赖)或通过共享
$scope
链相互通信。