我可以伸展RequireJS为我的应用程序提供依赖注入多少?举个例子,假设我有一个我希望成为单身人士的模特。自执行getInstance()中不是单例 - 类型单例,而是上下文强制单例(每个“上下文”一个实例)。我想做点像......
require(['mymodel'], function(mymodel) {
...
}
让mymodel成为MyModel类的一个实例。如果我要在多个模块中执行此操作,我希望mymodel是相同的共享实例。
我已经通过制作mymodel模块成功完成了这项工作:
define(function() {
var MyModel = function() {
this.value = 10;
}
return new MyModel();
});
这种用法是预期的还是常见的,还是我滥用RequireJS?有没有更合适的方法可以使用RequireJS执行依赖注入?谢谢你的帮助。仍在努力掌握这一点。
答案 0 :(得分:60)
这实际上不是依赖注入,而是服务位置:您的其他模块通过字符串“key”请求“类”,并获取“服务定位器”(在本例中为RequireJS)具有的实例已被连线以供他们使用。
依赖注入将涉及返回MyModel
构造函数,即return MyModel
,然后在中心组合根中将MyModel
的实例注入到其他实例中。我在这里汇总了一个如何运作的示例:https://gist.github.com/1274607 (也在下面引用)
这样,组合根确定是否分发MyModel
的单个实例(即使其成为单一作用域)或者为需要它的每个类(实例作用域)或其间的某个类分发新实例。该逻辑既不属于MyModel的定义,也不属于要求其实例的类。
(旁注:虽然我没有使用它,wire.js是一个看起来很酷的JavaScript的完整依赖注入容器。)
你并不一定像你一样使用它来滥用RequireJS,虽然你所做的似乎有点迂回,即声明一个类而不是返回它的新实例。为什么不这样做呢?
define(function () {
var value = 10;
return {
doStuff: function () {
alert(value);
}
};
});
您可能缺少的类比是模块在大多数其他语言中等同于“命名空间”,尽管您可以将函数和值附加到命名空间。 (因此更像Python而不是Java或C#。)它们不等同于类,尽管如您所示,您可以使模块的导出等于给定类实例的导出。
因此,您可以通过将函数和值直接附加到模块来创建单例,但这有点像使用静态类创建单例:它非常不灵活,通常不是最佳实践。但是,大多数人都把它们的模块视为“静态类”,因为正确地构建一个依赖注入系统需要从一开始就考虑很多,这在JavaScript中并不是真正的标准。
这里是https://gist.github.com/1274607内联:
// EntryPoint.js
define(function () {
return function EntryPoint(model1, model2) {
// stuff
};
});
// Model1.js
define(function () {
return function Model1() {
// stuff
};
});
// Model2.js
define(function () {
return function Model2(helper) {
// stuff
};
});
// Helper.js
define(function () {
return function Helper() {
// stuff
};
});
// composition root, probably your main module
define(function (require) {
var EntryPoint = require("./EntryPoint");
var Model1 = require("./Model1");
var Model2 = require("./Model2");
var Helper = require("./Helper");
var entryPoint = new EntryPoint(new Model1(), new Model2(new Helper()));
entryPoint.start();
});
答案 1 :(得分:3)
如果你认真对待DI / IOC,你可能会对wire.js感兴趣:https://github.com/cujojs/wire
我们使用服务重定位(如Domenic描述,但使用curl.js而不是RequireJS)和DI(使用wire.js)的组合。在测试工具中使用模拟对象时,服务重定位非常方便。 DI似乎是大多数其他用例的最佳选择。
答案 2 :(得分:1)
自执行getInstance()中不是单例 - 键入单例,但是 上下文强制执行的单例(每个“上下文”一个实例)。
我建议它仅用于静态对象。将静态对象作为您在require / define块中加载的模块是完全没问题的。然后创建一个只包含静态属性和函数的类。然后,您拥有等效的数学对象,其中包含PI,E,SQRT等常量以及round(),random(),max(),min()等函数。非常适合创建可以随时注入的实用程序类。
而不是:
define(function() {
var MyModel = function() {
this.value = 10;
}
return new MyModel();
});
创建一个实例,将模式用于静态对象(其中值始终与Object永远不会被实例化):
define(function() {
return {
value: 10
};
});
或
define(function() {
var CONSTANT = 10;
return {
value: CONSTANT
};
});
如果要传递实例(使用返回新MyModel()的模块的结果;),则在initialize函数中传递捕获当前状态/上下文的变量或传递Object包含有关模块需要了解的状态/上下文的信息。