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