简体   繁体   中英

What are the Advantages and Disadvantages Between These Two JavaScript Patterns?

These two JavaScript patterns are very similar. I would like to know which one is better and why and how either one can be improved.

First Approach:

"MODULE" in window || (window.MODULE = {} );

MODULE.utils = (function ($) {

    var utils = {};

    //public
    utils.todo = function() {
        //#
    }

    //private
    function init() {
        //#
    }

    init();

    return utils;
}(jQuery));

Second Approach :

"MODULE" in window || (window.MODULE = {} );

MODULE.utils = (function() {

    function todo(){
        //#
    }

    function init() {
        //#
    }

    return {
        init:init
    }

})();


$(function() {
    MODULE.utils.init();
});

Both of your options don't really have much in the way of pros or cons, it's more just about personal preference. Both could be adjusted to provide scope a bit better.

I have my own preference, it relies on Underscore . It doesn't really promote private variables or functions but I rarely find this an issue. If you want to introduce jQuery, etc, it would be best to wrap in an anonymous function to $ is actually jQuery (or an interchangeable library).

As you'll see below, my preference requires a little more code to get you going (although some of it's not necessary), but having tried a few variations of what you originally proposed, I've found that my solutions lends itself to more understandable code and it's easier for other devs to get the grasp of what's going on, especially if they've got experience with Backbone.View .

EDIT: Wrapped in an anonymous function to demonstrate integrating jQuery and protected scope.

var MyNamespace = MyNamespace || {};

(function($, MyNamespace) {

    MyNamespace.MyModule = function(options) {
        this.defaults = this.defaults || {};
        // have had trouble with _.defaults so _.extend instead
        this.options = _.extend({}, this.defaults, options);
        this.initialize.call(this);
        // define private stuff in here if you want
    };

    _.extend(MyNamespace.MyModule.prototype, {

        defaults: {
            myOption: "test"
        },

        initialize: function()
        {
            // ensure this always refers to our MyModule instance
            _.bindAll(this);
            this.$el = $("#some-widget");
            // Look Ma! log is already binded to this!
            this.$el.on("click", this.log);
        },

        setMyOption: function(value)
        {
            this.options.myOption = value;
        },

        log: function()
        {
            console.log("myOption: ", this.options.myOption);
        }

    });

})(jQuery, MyNamespace) 

var myModule = new MyNamespace.MyModule({ myOption: "Hey SO!" });
myModule.log(); // -> myOption: Hey SO!
myModule.setMyOption("Setter");
myModule.log(); // -> myOption: Setter
 "MODULE" in window || (window.MODULE = {} ); 

Why do that? We're already in the global scope here, right, so we can just do:

var MODULE = MODULE || {};

Other that that, the only real difference (other than style) is in the first example init is called immediately from within the "module," while in the second example you call init manually at some later point in time (even if it's immediately after the module loads in this case). So, if you need to delay the call to init , the second is preferable; if you want it to happen immediately, the first is preferable (aside from preferences about style).

The second approach assumes the variable named $ is a function that accepts a single argument that is also a function — probably an assumption that $ == jQuery . This may not always be true. In the first approach, you guarantee that $ == jQuery within the scope of your module because you pass it in as an argument to the anonymous function that initializes your module.

Beyond that, there's not a lot of difference between the two. I prefer the second approach for exposing public methods so that my syntax looks the same for both public and private methods, and so that I have to explicitly specify which methods are public. But that's just stylistic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM