requirejs循环依赖项和函数对象

时间:2015-05-12 12:30:37

标签: javascript requirejs classloader circular-dependency

是否可以区分结构构建(如继承)和运行时依赖(在方法调用中)所需的依赖项。

一个小例子:

2“班级”:彼此依赖的父亲和孩子

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);
});

使用导出时,您只能扩展一个对象(如果我是正确的)。那么有可能建立这样的结构吗?

我真正尝试做的事情:有一个自动的“类”加载(分隔文件),它加载一个更大的模型中的所有依赖项,它具有一些循环依赖项。一些依赖项需要立即(继承),有些只在对象启动后才需要。我无法找到解决问题的好办法。

2 个答案:

答案 0 :(得分:2)

这是(IMO)一个多变的有效问题,从昨天开始困惑我。如果我是你,我会考虑优先顺序:

  1. 拥抱鸭子。一个有用的$('.element').click(function () { var offsetTop = $('.destination').offset().top; $('html,body').stop(true, false).animate({ scrollTop: offsetTop }, 800); }); 类可能有像Childplay()这样的方法,所以"如果它像鸭子一样走路而且像鸭子一样嘎嘎叫......"变成"如果它像孩子一样玩耍,像孩子一样哭泣,那么它就是一个孩子":

    cry()

    这种方法的另一个好处(在一般情况下)是你实际上是在Javascript中使用等效的接口进行编程。即思考过程是"我需要// 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; }); 为什么? - 播种和哭泣。 - 然后对我来说,我得到的对象有这两种方法就足够了。我不关心它的确切实现。"

  2. 这是技术性和丑陋的,但(至少IMO)可以接受的丑陋:你可以引入第三种依赖来打破周期,这与周期一样。即:

    Child

    捕获:您必须确保从某个地方需要// 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(即FatherBaseChild.js)。

  3. 可以考虑涉及命名空间对象的解决方案(即返回包含构造函数Father.jsfamily的{​​{1}}对象),但我认为它太难看了。

答案 1 :(得分:-1)

我知道这不是很好,并且正确地打破了一些优化和一些约定(比如处理具有相同名称的模块)。所以这是一个解决方案,它复制了全球范围内的所有模块。

<强> 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");
});

要同步加载(在更复杂的项目上),我使用一个中介来跟踪所需的加载,并在加载所有内容时触发事件。

而不是窗口,您可以使用https://stackoverflow.com/a/5573049/228763在其他平台上使用。