Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript singleton patterns - differences?

This may seem like a silly question, but what are the functional differences, if any, between these two patterns? Is there no real functional difference and it's just a matter of organization preference? What are some instances when you would want to use one and not the other? I'm trying to find a design pattern I feel most comfortable with. Thanks!

$(function(){
    Core.init();
});

var Core = {

    init: function() {
       //some initialization code here
    }

    _plugins: function() {
       //instantiate some plugins here
    }

    _display: function() {
       //some more code here
    }

    _otherfunctions: function() {
       ....
    }

}

and

$(function(){
    Core.init();
    Plugins.init();
    Display.init();
});

var Core = {

    init: function() {
       //some initialization code here
    }
}

var Plugins = {
    init: function() {
       //start plugins
    }

    _modify: function() {
      //more code
   }
}

var Display = {
    init: function() {
     //some init code
    }
}
like image 239
Paul Erdos Avatar asked Nov 04 '22 11:11

Paul Erdos


2 Answers

The main organizational difference is that the first pattern pollutes the global namespace less.

If you do want to separate your code into packages like in the second example, then the better way, within your example, would be:

$(function(){
    Core.init();
});

var Core = {

    init: function() {
       //some initialization code here
    },

    plugins: {
        init: function() {
        //start plugins
        }

        _modify: function() {
        //more code
        }
    },

    display: {
        init: function() {
        //some init code
        }
    }
}

and refer to the packages through your main namespace:

Core.plugins.init();

I am not saying that this is the best way to do so in general (some of it is a matter of preference, like private members and methods), but in your example - I'd prefer mine.

like image 188
ZenMaster Avatar answered Nov 09 '22 11:11

ZenMaster


Have a look at this framework I have built. Seems to work pretty well.

var gtg = gtg || {};

(function () {
    var _this = this;

    this.registerNamespace = function (namespace) {
        var root = window,
            parts = namespace.split("."),
            i;

        for (i = 0; i < parts.length; i++) {
            if (typeof root[parts[i]] === "undefined") {
                root[parts[i]] = {};
            }
            root = root[parts[i]];
        }

        return this;
    };

}).call(gtg);

// Register Namespaces
gtg.registerNamespace("gtg.core");
gtg.registerNamespace("gtg.infoBar");
gtg.registerNamespace("gtg.navBar");
gtg.registerNamespace("gtg.tabBar");
gtg.registerNamespace("gtg.utils");

(function () {
    var _this = this;

    this.initialize = function () { };

}).call(gtg.core);

(function () {
    var _this = this,
        $container,
        $messageContainer,
        $message;

    function configureMessage(message) {
        var className = "info",
            types = ["error", "info", "warning"];

        for (var i in types) {
            $message.removeClass(types[i]);
        }

        switch (message.MessageType) {
            case 0:
                className = "error"
                break;
            case 1:
                className = "info"
                break;
            case 2:
                className = "warning"
                break;
        }

        $message.addClass(className).html(message.Message);
    }

    this.initialize = function () {
        $container = $(".info-bar-container");
        $messageContainer = $container.find(".message-container");
        $message = $messageContainer.find(".message");

        $messageContainer.find(".close a").bind("click", function () {
            _this.close();
        });
    };

    this.close = function () {
        $messageContainer.fadeOut(300, function () {
            $container.slideUp(300);
        });
    };

    this.show = function (message) {
        if ($container.css("display") !== "none") {
            $messageContainer.fadeOut(300, function () {
                configureMessage(message);
                $messageContainer.fadeIn(300);
            });
        } else {
            $container.slideDown(300, function () {
                configureMessage(message);
                $messageContainer.fadeIn(300);
            });
        }
    };

}).call(gtg.infoBar);

(function () {
    var _this = this;

    function initializeNavBar() {
        var paths = window.location.pathname.split("/"),
            navId;

        $("#nav-bar ul.top-nav li a[data-nav]").bind("click", function () {
            _this.switchNav($(this));
        });

        if (paths[1] != "") {
            switch (paths[1]) {
                case "Customer":
                    navId = "customers-nav";
                    break;
                case "Order":
                    navId = "orders-nav";
                    break;
                case "Product":
                    navId = "products-nav";
                    break;
                case "Report":
                    navId = "reports-nav";
                    break;
                case "Tool":
                    navId = "tools-nav";
                    break;
            }

            if (navId != "") {
                _this.switchNav($('#nav-bar ul.top-nav li a[data-nav="' + navId + '"]'));
            }

        } else {
            _this.switchNav($('#nav-bar ul.top-nav li a[data-nav="home-nav"]'));
        }
    }

    this.initialize = function () {
        initializeNavBar();
    };

    this.switchNav = function (navItem) {
        $("#nav-bar ul.top-nav li a[data-nav]").each(function (i) {
            $(this).removeClass("selected");
            $("#" + $(this).data("nav")).hide();
        });

        navItem.addClass("selected");
        $("#" + navItem.data("nav")).show();
    };

}).call(gtg.navBar);

(function () {
    var _this = this;

    this.initialize = function () {
        $(".tab-bar ul li a[data-tab-panel]").bind("click", function () {
            _this.switchTab($(this));
        });
    };

    this.switchTab = function (tab) {
        $(".tab-bar ul li a[data-tab-panel]").each(function (i) {
            $(this).removeClass("selected");
            $("#" + $(this).data("tab-panel")).hide();
        });

        tab.addClass("selected");
        $("#" + tab.data("tab-panel")).show();
    };

}).call(gtg.tabBar);

(function () {
    var _this = this;

    this.focusField = function (fieldId) {
        $("#" + fieldId).select().focus();
    };

    this.loadJQTemplate = function (templateName, callback) {
        $.get("/Content/JQTemplates/" + templateName + ".html", function (template) {
            callback(template);
        });
    };

}).call(gtg.utils);

$(document).ready(function () {
    gtg.core.initialize();
    gtg.infoBar.initialize();
    gtg.navBar.initialize();
    gtg.tabBar.initialize();
});
like image 30
Sam Avatar answered Nov 09 '22 13:11

Sam