使用模块化方法构建JavaScript应用程序

时间:2013-04-18 18:16:39

标签: javascript oop interpreter modularity prototypal-inheritance

我正在尝试编写一个足够大的javaScript应用程序,模块化可能是一个好主意。我使用着名的继承函数来使对象从具有参数的构造函数继承。问题是我得到一个错误,传递给继承函数的父是未定义的。这是因为,当调用inherit时,尚未定义父构造函数。

我想出了一些解决这个问题的丑陋方法:

  1. 在父母(yuk)之后声明所有子构造函数。

  2. 将所有原型分配绑定到自定义事件,并使用有序的回调链来确保按顺序分配所有原型(可能存在潜在的原型)。

  3. 从构造函数所在的代码区域中移动所有原型赋值,并将它们合并(并放逐)到某些“assign prototypes”函数(第一项yuk的两倍,不是吗?)。

  4. 底线是我不希望基于我的构造函数,方法和对象在代码中按照加载/解释代码的顺序编写的顺序。我希望我的代码易于扩展,并且相关代码组合在一起,因此很容易理解(即,原型赋值是否应该靠近构造函数声明/定义?)。

    我将模块放在单独的文件中,并在将它们发送到浏览器之前使用PHP脚本将它们全部附加在一起。 PHP脚本只确保首先包含声明命名空间的文件,之后它将js文件与glob连接。

    我写了一个小脚本,完全展示了我遇到的问题。它是is live at this url。屏幕是白色的,因为没有html - 我在这里使用控制台进行分析。

    /*global console, jQuery, $, myNS: true*/
    /*jslint browser: true*/
    
    /*
     * This file is deliberately set as the first file in the php glob.
     */
    var myNS = (function (myNS, $, window, undefined) {
        "use strict";
    
        /*
         * @param {object} coords -- e.g. {x: 3, y: 26}
         */
        myNS = function (coords) {
            return new myNS.CartesianLoc(coords);
        };
    
        // static methods
        myNS.inherit = function (parent) {
            function F() {}
            F.prototype = parent.prototype;
            return new F();
        };
        myNS.getWinCenter = function () {
            return {
                x : $(window).width() / 2,
                y : $(window).height() / 2
            };
        };
    
        // prototype
        myNS.prototype = {
            log: function () {
                if (window.console) {
                    console.log(this);
                }
            }
        };
    
        return myNS;
    }(myNS, jQuery, window));
    
    
    
    /*
     * This is another file.
     */
    (function (myNS, $, window, undefined) {
        "use strict";
        /*
         *  CartesianLoc constructor
         *
         *  @param {object} coords -- given in a conceptual
         *  Cartesian space where the origin (0,0) is
         *  the middle of whatever screen
         */
        function CartesianLoc(coords) {
            myNS.Loc.call(this, coords);
        }
        CartesianLoc.prototype = myNS.inherit(myNS.Loc);
        CartesianLoc.prototype.constructor = CartesianLoc;
    
        CartesianLoc.prototype.getWinCoords = function () {
            return {
                x: myNS.getWinCenter().x + this.x,
                y: myNS.getWinCenter().y + this.y
            };
        };
    
        myNS.CartesianLoc = CartesianLoc;
    }(myNS, jQuery, window));
    
    
    
    /*
     * This is another file.
     */
    (function (myNS, $, window, undefined) {
        "use strict";
        // Location constructor
        function Loc(coords) {
            this.x = coords.x;
            this.y = coords.y;
        }
        Loc.prototype = myNS.inherit(myNS);
        Loc.prototype.constructor = Loc;
    
        Loc.prototype.translate = function (coords) {
            this.loc.x += coords.x;
            this.loc.y += coords.y;
            return this;
        };
    
        myNS.Loc = Loc;
    }(myNS, jQuery, window));
    
    
    
    /*
     * Application js file
     *
     */
    
    (function (myNS, $, window, undefined) {
        "use strict";
    
        $(document).ready(function (event) {
            if (console) {
                console.log("%o", new myNS({x: 100, y: -45}));
            }
        });
    
    }(myNS, jQuery, window));
    

    感谢你给我的任何帮助或想法!
    克里斯

1 个答案:

答案 0 :(得分:0)

我不确定这是一个合理的练习还是凌乱,但我创建了一个在document.ready上触发的自定义事件,并将所有在回调中分配原型的代码放置到该事件中。我知道我正在添加一个事件,当另一个事件被触发时触发它(这看起来毫无意义),但我希望自定义事件是一个被监听的事件,以防我想要改变以后触发它的方式。

/*global console, jQuery, $, myNS: true*/
/*jslint browser: true*/

/*
 * This file is deliberately set as the first file in the php glob.
 */
var myNS = (function (myNS, $, window, undefined) {
    "use strict";

    /*
     * @param {object} coords -- e.g. {x: 3, y: 26}
     */
    myNS = function (coords) {
        return new myNS.CartesianLoc(coords);
    };

    // Triggered after all constructors have been defined
    $(document).ready(function (event) {
        $(document).trigger("myNS");
    });

    // static methods
    myNS.inherit = function (parent) {
        function F() {}
        F.prototype = parent.prototype;
        return new F();
    };
    myNS.getWinCenter = function () {
        return {
            x : $(window).width() / 2,
            y : $(window).height() / 2
        };
    };

    // prototype
    myNS.prototype = {
        log: function () {
            if (window.console) {
                console.log(this);
            }
        }
    };

    return myNS;
}(myNS, jQuery, window));



/*
 * This is another file.
 */
(function (myNS, $, window, undefined) {
    "use strict";
    /*
     *  CartesianLoc constructor
     *
     *  @param {object} coords -- given in a conceptual
     *  Cartesian space where the origin (0,0) is
     *  the middle of whatever screen
     */
    function CartesianLoc(coords) {
        myNS.Loc.call(this, coords);
    }
    $(document).on('myNS', function (event) {
        CartesianLoc.prototype = myNS.inherit(myNS.Loc);
        CartesianLoc.prototype.constructor = CartesianLoc;

        CartesianLoc.prototype.getWinCoords = function () {
            return {
                x: myNS.getWinCenter().x + this.x,
                y: myNS.getWinCenter().y + this.y
            };
        };
    });
    myNS.CartesianLoc = CartesianLoc;
}(myNS, jQuery, window));



/*
 * This is another file.
 */
(function (myNS, $, window, undefined) {
    "use strict";
    // Location constructor
    function Loc(coords) {
        this.x = coords.x;
        this.y = coords.y;
    }
    $(document).on('myNS', function (event) {
        Loc.prototype = myNS.inherit(myNS);
        Loc.prototype.constructor = Loc;

        Loc.prototype.translate = function (coords) {
            this.loc.x += coords.x;
            this.loc.y += coords.y;
            return this;
        };
    });
    myNS.Loc = Loc;
}(myNS, jQuery, window));



/*
 * Application js file
 *
 */

(function (myNS, $, window, undefined) {
    "use strict";

    $(document).ready(function (event) {
        if (console) {
            console.log("%o", new myNS({x: 100, y: -45}));
        }
    });

}(myNS, jQuery, window));