requirejs 循环依赖和函数对象
requirejs circular dependencies and function objects
是否可以区分结构构建所需的依赖项(如继承)和运行时依赖项(在方法调用中)。
一个小例子:
2 "classes": 相依为命的父子
Father.js
define(['Child'], function (Child) {
function Father() {};
Father.prototype.childs = [];
Father.prototype.addChild = function (c) {
if (!(c instanceof Child)) {
alert("nope");
}
}
return Father;
});
Child.js
define(['Father'], function(Father){
function Child(){
this.father = [];
}
Child.prototype.setFather = function(f){
if(!(f instanceof Father)){
alert("false");
}
}
return Child;
});
和一个app.js
requirejs(['Child', 'Father'], function(Child, Father){
var c = new Child();
var f = new Father();
c.setFather(f);
f.addChild(c);
});
当使用 export 时,您只能扩展一个对象(如果我是正确的)。那么是否可以构建这样的结构?
我实际尝试做的事情:有一个自动的"class"-loading(分离的文件),它将所有依赖项加载到一个更大的模型中,它有一些循环依赖项。一些依赖性立即需要(继承),而一些仅在对象启动后才需要。而且我找不到解决问题的好方法。
这是 (IMO) 一个不同的有效问题,从昨天开始我就困惑了。如果我是你,我会考虑什么,按优先顺序:
拥抱鸭子打字。一个有用的 Child
class 可能有像 play()
和 cry()
这样的方法,所以 "if it walks like a duck and quacks like a duck..." 变成 "if it plays like child and cries like a child, then it is a child":
// Father.js
define([], function() {
function Father() {};
Father.prototype.childs = [];
Father.prototype.addChild = function (c) {
if( !c || typeof(c.play) !== 'function' || typeof(c.cry) !== 'function' ) {
alert("nope");
}
}
return Father;
});
这种方法的另一个好处(在一般情况下)是您实际上是针对 Javascript 中的等效接口进行编程。 IE。思维过程是"What am I going to need a Child
for? -Playing and crying. -Then it is enough for me that the object I get has these 2 methods. I do not care about the exact implementation of it."
这是技术性的且丑陋,但(至少在 IMO 上)丑陋得可以接受:您可以引入第三个依赖项来打破循环,这在循环中很常见。即:
// Father.js
define([], function() {
function Father() {};
Father.prototype.childs = [];
return Father;
});
// Child.js
define(['Father'], function(Father){
function Child(){
this.father = [];
}
Child.prototype.setFather = function(f){
if(!(f instanceof Father)){
alert("false");
}
}
return Child;
});
// FatherAugmentor.js (any ideas for a better name?)
define(['Father', 'Child'], function(Father, Child) {
Father.prototype.addChild = function (c) {
if (!(c instanceof Child)) {
alert("nope");
}
}
});
一个问题: 您必须确保从某处需要 FatherAugmentor
!或者,您可以使用名称(再次丑陋),以便上面的 FatherAugmentor
变成 Father
并且上面的 Father
重命名为,例如FatherBase
:
// FatherBase.js
define([], function() {
// exactly the same as `Father.js` from above
});
// Child.js
define(['FatherBase'], function(Father){
// exactly the same as `Child.js` from above
});
// Father.js
define(['FatherBase', 'Child'], function(Father, Child) {
// exactly the same as `FatherAugmentor.js` from above
});
有了这个,您可以确保任何请求 Father
将获得完整的 class,但您必须小心地在作为循环一部分的文件中使用 FatherBase
(即 Child.js
和 Father.js
)。
可以考虑涉及命名空间对象的解决方案(即 return 一个包含 family.Father
和 family.Child
构造函数的 family
对象),但我觉得它太丑了。
我知道这不是很好并且适当地打破了一些优化和一些约定(比如处理具有相同名称的模块)。所以这是一个复制全局范围内所有模块的解决方案。
Child.js
define(['Father'], function(){
// var Father = require("Father");
function Child(){
this.father = [];
}
Child.prototype.setFather = function(f){
if(!(f instanceof Father)){
alert("false");
}
}
window.Child = Child;
});
Father.js
define(['Child'], function () {
function Father() {};
Father.prototype.childs = [];
Father.prototype.addChild = function (c) {
if (!(c instanceof Child)) {
alert("nope");
}
};
window.Father = Father;
});
app.js
requirejs(['Child', 'Father'], function(){
var c = new Child();
var f = new Father();
c.setFather(f);
f.addChild(c);
console.log("done");
});
为了同步加载(在一个更复杂的项目上),我使用了一个中介来跟踪所需的加载,并在加载所有内容时触发一个事件。
您可以使用 而不是 window 在其他平台上工作。
是否可以区分结构构建所需的依赖项(如继承)和运行时依赖项(在方法调用中)。
一个小例子:
2 "classes": 相依为命的父子
Father.js
define(['Child'], function (Child) {
function Father() {};
Father.prototype.childs = [];
Father.prototype.addChild = function (c) {
if (!(c instanceof Child)) {
alert("nope");
}
}
return Father;
});
Child.js
define(['Father'], function(Father){
function Child(){
this.father = [];
}
Child.prototype.setFather = function(f){
if(!(f instanceof Father)){
alert("false");
}
}
return Child;
});
和一个app.js
requirejs(['Child', 'Father'], function(Child, Father){
var c = new Child();
var f = new Father();
c.setFather(f);
f.addChild(c);
});
当使用 export 时,您只能扩展一个对象(如果我是正确的)。那么是否可以构建这样的结构?
我实际尝试做的事情:有一个自动的"class"-loading(分离的文件),它将所有依赖项加载到一个更大的模型中,它有一些循环依赖项。一些依赖性立即需要(继承),而一些仅在对象启动后才需要。而且我找不到解决问题的好方法。
这是 (IMO) 一个不同的有效问题,从昨天开始我就困惑了。如果我是你,我会考虑什么,按优先顺序:
拥抱鸭子打字。一个有用的
Child
class 可能有像play()
和cry()
这样的方法,所以 "if it walks like a duck and quacks like a duck..." 变成 "if it plays like child and cries like a child, then it is a child":// Father.js define([], function() { function Father() {}; Father.prototype.childs = []; Father.prototype.addChild = function (c) { if( !c || typeof(c.play) !== 'function' || typeof(c.cry) !== 'function' ) { alert("nope"); } } return Father; });
这种方法的另一个好处(在一般情况下)是您实际上是针对 Javascript 中的等效接口进行编程。 IE。思维过程是"What am I going to need a
Child
for? -Playing and crying. -Then it is enough for me that the object I get has these 2 methods. I do not care about the exact implementation of it."这是技术性的且丑陋,但(至少在 IMO 上)丑陋得可以接受:您可以引入第三个依赖项来打破循环,这在循环中很常见。即:
// Father.js define([], function() { function Father() {}; Father.prototype.childs = []; return Father; }); // Child.js define(['Father'], function(Father){ function Child(){ this.father = []; } Child.prototype.setFather = function(f){ if(!(f instanceof Father)){ alert("false"); } } return Child; }); // FatherAugmentor.js (any ideas for a better name?) define(['Father', 'Child'], function(Father, Child) { Father.prototype.addChild = function (c) { if (!(c instanceof Child)) { alert("nope"); } } });
一个问题: 您必须确保从某处需要
FatherAugmentor
!或者,您可以使用名称(再次丑陋),以便上面的FatherAugmentor
变成Father
并且上面的Father
重命名为,例如FatherBase
:// FatherBase.js define([], function() { // exactly the same as `Father.js` from above }); // Child.js define(['FatherBase'], function(Father){ // exactly the same as `Child.js` from above }); // Father.js define(['FatherBase', 'Child'], function(Father, Child) { // exactly the same as `FatherAugmentor.js` from above });
有了这个,您可以确保任何请求
Father
将获得完整的 class,但您必须小心地在作为循环一部分的文件中使用FatherBase
(即Child.js
和Father.js
)。可以考虑涉及命名空间对象的解决方案(即 return 一个包含
family.Father
和family.Child
构造函数的family
对象),但我觉得它太丑了。
我知道这不是很好并且适当地打破了一些优化和一些约定(比如处理具有相同名称的模块)。所以这是一个复制全局范围内所有模块的解决方案。
Child.js
define(['Father'], function(){
// var Father = require("Father");
function Child(){
this.father = [];
}
Child.prototype.setFather = function(f){
if(!(f instanceof Father)){
alert("false");
}
}
window.Child = Child;
});
Father.js
define(['Child'], function () {
function Father() {};
Father.prototype.childs = [];
Father.prototype.addChild = function (c) {
if (!(c instanceof Child)) {
alert("nope");
}
};
window.Father = Father;
});
app.js
requirejs(['Child', 'Father'], function(){
var c = new Child();
var f = new Father();
c.setFather(f);
f.addChild(c);
console.log("done");
});
为了同步加载(在一个更复杂的项目上),我使用了一个中介来跟踪所需的加载,并在加载所有内容时触发一个事件。
您可以使用 而不是 window 在其他平台上工作。