Javascript 使用RequireJS的依赖注入

Javascript 使用RequireJS的依赖注入,javascript,requirejs,Javascript,Requirejs,我可以拉伸多少RequireJS来为我的应用程序提供依赖注入?举个例子,假设我有一个模型,我想成为一个单身汉。不是自强制getInstance()类型singleton中的singleton,而是上下文强制的singleton(每个“上下文”一个实例)。我想做一些像 require(['mymodel'], function(mymodel) { ... } 并使mymodel成为mymodel类的实例。如果在多个模块中执行此操作,我希望mymodel是相同的共享实例 我通过如下方式制作

我可以拉伸多少RequireJS来为我的应用程序提供依赖注入?举个例子,假设我有一个模型,我想成为一个单身汉。不是自强制getInstance()类型singleton中的singleton,而是上下文强制的singleton(每个“上下文”一个实例)。我想做一些像

require(['mymodel'], function(mymodel) {
   ...
}
并使mymodel成为mymodel类的实例。如果在多个模块中执行此操作,我希望mymodel是相同的共享实例

我通过如下方式制作mymodel模块,成功地完成了这项工作:

define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});

这种用法是预期的、常见的还是我滥用了RequireJS?有没有更合适的方法可以用RequireJS执行依赖项注入?谢谢你的帮助。仍在努力掌握这一点。

这实际上不是依赖注入,而是服务位置:您的其他模块通过字符串“key”请求一个“class”,并返回一个“service locator”(在本例中为RequireJS)已连接好的实例

依赖项注入将涉及返回
MyModel
构造函数,即
返回MyModel
,然后在中心合成根中将
MyModel
的实例注入其他实例。我在这里收集了一个示例,说明这是如何工作的:(下面也引用)

通过这种方式,组合根确定是分发
MyModel
的单个实例(即使其成为单实例范围),还是为每个需要它的类分发新实例(实例范围),或者介于两者之间。这种逻辑既不属于MyModel的定义,也不属于请求MyModel实例的类

(旁注:虽然我还没有使用它,但它是一个成熟的JavaScript依赖注入容器,看起来非常酷。)


虽然您所做的事情似乎有点迂回,即声明一个类而不是返回一个新的类实例,但您不一定是在滥用RequireJS。为什么不做下面的事情呢

define(function () {
    var value = 10;

    return {
        doStuff: function () {
            alert(value);
        }
    };
});
您可能缺少的类比是,在大多数其他语言中,模块等同于“名称空间”,尽管名称空间可以附加函数和值。(因此更像Python而不是Java或C。)它们并不等同于类,尽管如您所示,您可以使模块的导出等同于给定类实例的导出

因此,您可以通过将函数和值直接附加到模块来创建单例,但这有点像通过使用静态类来创建单例:它非常不灵活,通常不是最佳实践。然而,大多数人确实将他们的模块视为“静态类”,因为正确地为依赖注入构建系统需要从一开始就进行大量思考,而这在JavaScript中并不是真正的标准


以下是在线:


如果您认真对待DI/IOC,您可能会对wire.js感兴趣:

我们结合使用服务重新定位(如Domenic所述,但使用curl.js而不是RequireJS)和DI(使用wire.js)。在测试工具中使用模拟对象时,服务重新定位非常方便。DI似乎是大多数其他用例的最佳选择

不是自强制getInstance()类型singleton中的singleton,而是 上下文强制的单例(每个“上下文”一个实例)

我建议只对静态对象使用它。在require/define块中使用一个静态对象作为加载模块是非常好的。然后创建一个只有静态属性和函数的类。然后,您就得到了Math对象的等价物,该对象具有PI、E、SQRT等常量和round()、random()、max()、min()等函数。非常适合创建可随时注入的实用程序类

与此相反:

define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});
创建实例时,使用静态对象的模式(其中值始终与对象相同,永远不会实例化对象):


如果要传递实例(使用具有return new MyModel();)的模块的结果),则在初始化函数中传递一个捕获当前状态/上下文的变量,或传递包含模块需要了解的状态/上下文信息的对象

说得好。非常感谢。我之所以使用一个类,实例化它,然后返回它,是因为我考虑将MyModel函数/类移出到它自己的JS文件中,并让MyModel模块返回一个实例。这将使RequireJS看起来更像DI容器。但是,你是对的,没有组合根,它仍然不是DI。我也很欣赏你的最后一段。这是有道理的。我来自大量使用DI的语言,并试图找出为什么它在JS中不常用。缺少注释和静态类型是否会让它变得过于霸道?我最近开始做DI风格的模块,发现它非常好,实际上,原因与静态语言相同(主要是可测试性和关注点分离)。缺少接口使事情变得不那么明确,但也使插入存根实例变得更容易:只需传入带有适当成员的对象文本即可。因此,如果可以,我建议您使用DI类型的解决方案,即使是JavaScript。人们仍然在研究大规模JavaScript,以及模块如何融入其中,但我认为DI仍然是一个很好的方法。介意分享一下您如何使用DI风格的模块吗?或多或少类似于链接的要点,尽管这是与较旧的代码基集成,我们没有组合根,而是有许多位于服务的单例模块,它们在其中组成一个小对象图,然后适当地导出。我在Domenic.doh网站上提供了一个稍微丰富一些的示例,主要基于我们实际代码库中的代码,感谢您的帮助。没有看到多梅尼克已经建议的电线+1至Domenic:)
define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});
define(function() {
    return {
       value: 10
    };
});
define(function() {
    var CONSTANT = 10;
    return {
       value: CONSTANT
    };
});