开发者

What's the difference between these two JavaScript patterns

开发者 https://www.devze.com 2023-04-10 05:29 出处:网络
I am trying to organize my JavaScript better. My goal is to have modular architecture that I can break into separate files (sitename.js, sitename.utils.js etc).

I am trying to organize my JavaScript better. My goal is to have modular architecture that I can break into separate files (sitename.js, sitename.utils.js etc).

I'd like to know what are advantages and disadvantages of these开发者_如何学C two patterns and which one is more suitable for breaking into modules that live in separate files.

PATTERN #1 (module pattern)

var MODULE = (function () {

    //private methods

    return {
        common: {
            init: function() {
                console.log("common.init");
            }
        },
        users: {
            init: function () {
                console.log("users.init");
            },
            show: function () {
                 console.log("users.show");
            }
        }
    }
})();

PATTERN #2 (singleton)

var MODULE = {
  common: {
    init: function() {
        console.log("common.init");
    }
  },

  users: {
    init: function() {
      console.log("users.init");
    },

    show: function() {
      console.log("users.show");
    }
  }
};


Personally, I recommend an extension of #1, as follows:

var Module = (function(Module) {
  // A comment
  Module.variable1 = 3;

  /**
   * init()
   */
  Module.init = function() {
    console.log("init");
  };

  // ...

  return Module;
})(Module || {});

I like this pattern for a couple reasons. One, documentation (specifically javadoc-style) look more natural when all your functions are declarations rather than a big hash. Two, if your submodules grow in size, it lets you break them into multiple files without any refactoring.

For example, if Module.Users were to go into its own file:

var Module = Module || {};
Module.Users = (function(Users) {
  /**
   * init()
   */
  Users.init = function() {
    console.log("Module.Users.init");
  };

  // ...

  return Users;
})(Module.Users || {});

Now "module.js" and "module.users.js" can be separate files, and they'll work regardless of the order they are loaded. Also note the local scoping of the module name - this is very handy if your module name is long, because you can take "MyApp.Users.EditScreen" and refer to it with a variable like "ES" within the scope of your module definition.


The first pattern allows for private variables, methods, etc via closures. For example:

var MODULE = (function () {

    var privateStuff = 'This is private';

    var doStuff = function(obj) {
        console.log('Doing stuff...');
        console.log(privateStuff);
    };

    return {
        common: {
            init: function() {
                console.log("common.init");
                doStuff(this);
            }
        },
        users: {
            init: function () {
                console.log("users.init");
            },
            show: function () {
                 console.log("users.show");
            }
        }
    }
})();

privateStuff and doStuff are not properties of the object, and are not available to anything but what's defined inside the function that returns MODULE. So showing an example for how to do this with #2 is not possible.

JS doesn't have the concept of private members, so you can't define them via a regular object literal. So if you need private stuff, go for the first option. If you don't, though, #2 is simpler.


Your code as written is pretty much the same. However, the first form is much easier to work with as you evolve your code, because it allows you to add private variables and functions. The second form doesn't support this, and you nearly always end up wanting the first form eventually.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号