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

Structuring a JavaScript app using a modular approach

本文关键字:JavaScript 应用程序 构建 模块化方法      更新时间:2023-09-26

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

我已经想出了一些丑陋的解决方案来解决这个问题:

  1. 将所有子构造函数声明在父构造函数之后。

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

  3. 将所有原型赋值从其构造函数所在的代码区域中移出,并将其合并(并放逐)到某个"赋值原型"函数中(是第1项的两倍,不是吗?)

底线是,我不希望在代码中编写构造函数、方法和对象的顺序必须基于代码加载/解释的顺序。我希望我的代码易于扩展,并与相关的代码组合在一起,以便易于理解(即,原型赋值不应该在构造函数声明/定义附近吗?)。

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

我写了一个小脚本,演示了我所遇到的问题。它是在这个网址上直播的。屏幕是白色的,因为没有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));

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

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

/*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));