JavaScript ‘Module Pattern’

The module pattern originally developed by Douglas Crockford and described on the Yahoo Interface Library blog for YUI components as a way to provide private and public encapsulation for JavaScript “classes”; on a side note, if you haven’t read or seen any of the articles on Doug’s site, you should go and read them now. Since YUI is not needed here at engfer(s), we felt we needed to make a more compelling example and adaptation to prove it to ourselves; moreover, it turns out that this could be an OOP-like solution for the jQuery library (Mootools handles classes well, but not encapsulation).

The Premise of the Module Pattern:

  • A class is actually defined as a function (will be aka “class” from this point)
  • The parameters you decide for this “class” are in fact the parameters for the constructor
  • The local variables and functions you create inside your “class” turn into private members
  • The return method for your “class” (remember it’s still a function) returns an object containing your public methods and variables
    • These methods have access to your “private” members, and you can feel free to use the accessor/mutator method pattern just like any other ‘ole OO language

Why the Module Pattern?

  • As hum-jumbled as this solution is, it is still clearer to an OO programmer to model true encapsulation
  • Public parts can touch the private parts, but the world can’t touch the class’ private parts (stop laughing)
    • Unfortunately, this pattern doesn’t allow private members to access public members, so you are limited (but not by too much since there are few occasions where this is needed)
  • You can piece together objects that follow the JavaBean convention

Ok, So Show Me Some Stuff That’s Useful

The example we picked is the simplified Person object. We’ll explain the squirrelly “options” code you see at the top of the object later, but for now let’s define our requirements. It would be useful if we could make the Person object:

  1. Created easily and logically (the Constructor). The YUI example uses some kind of funky init() method that is called after object creation; however, we’ like the typical Constructor pattern to be followed.
  2. Have a name and age that is accessible by the JavaBean convention (accessors/mutators)
  3. Have the ability to calculate the age in dog years (don’t ask me why, but it is interesting)

The Simple Person Object

To start out, let’s just create the scaffold for the Person ‘Module’:

// Creating the class
var Person = function( p_options ){
  // Begin Private Section

  // Begin Public Section
  return {
  };
};

In line 02 of our scaffold we created a ‘Person’ variable and we assigned it to a function with one parameter, “p_options”.

This is important as it will serve our as our constructor and parameters. Now technically, we can have multiple parameters to the “constructor” for things like name, age, etc, but we will show you something more interesting in a moment.

Since it is a function that we created, it needs to have a return statement. This return statement will return an Anonymous Object (‘{}’), which will contain our public members and API. That way, when we create a ‘new Person()’ object and store it to a variable, that variable only has access to the API from Person’s return statement (line 06). Let’s add a name and age to our Person; we’ll also add a method to calculate the age in dog years as well:

// Creating the class
var Person = function( p_options ){
  // Private name
  var m_name = options.name;
  // Private age
  var m_age = options.age;

  // Private method
  var calcAgeInDogYears = function(){
    return m_age / 7;
  };

  // Begin Public Section
  return {
  };
};

Ignoring the initialization of the two variables for the moment, we just created the two members m_age and m_name and the method calcAgeInDogYears(). Since these items are not in the return statement for Person, it will not be returned as part of the public API for Person, which makes these items part of private API. However, the public API does have access to these private API members and methods, so we can create a simple JavaBean pattern, so let’s add some accessors and mutators (and something to return the calculated age in dog years) to the public API:

// Creating the class
var Person = function( p_options ){
  // Private name
  var m_name = options.name;
  // Private age
  var m_age = options.age;

  // Private method
  var calcAgeInDogYears = function(){
    return m_age / 7;
  };

  // Begin Public Section
  return {
    // Name acceesor
    getName: function(){
      return m_name;
    },
    // Name mutator
    setName: function(name){
      m_name = name;
    },
    // Age accessor
    getAge: function(){
      return m_age;
    },
    // Age mutator
    setAge: function(age){
      m_age = age;
    },
    // Get person's age in dog years
    getAgeInDogYears: function(){
      return calcAgeInDogYears();
    }
  };
};

Now what’s squirrelly about the method definition for the public API is that it does have to follow the JavaScript object convention (not JSON): a comma-separated list of items that contain name + “: ” + assignment_type. Therefore, methods would follow ‘methodName: function( params ){}‘ and members would be ‘exampleCount: 0‘.

Let’s Fix the Constructor Parameters and the Private Member Initialization

Now, this could done as simply as follows (without much thought to optional parameters or null’s):

// Creating the class
var Person = function( p_name, p_age ){
  // Private name
  var m_name = p_name;
  // Private age
  var m_age = p_age;
  ...

However, we are limited; you must pass both parameters, and the private members can not have default values. The Mootools team have come up with an interesting solution to this problem: the Options class. This example is not about explaining how their Options class is implemented, but just how it works; however, if you’d like to see their implementation, you can do so here.

The premise of the Options class is to parse a comma-separated “param: param_value” JavaScript object and assign values to their equivalent “middle-man parameters“. You can then take these “middle-man parameters” and use them elsewhere.

This sounds awfully confusing so let’s just try an example. Let’s start with those “middle-man parameters“:

// Creating the class
var Person = function( p_options ){
  // Private options used for construction
  var options = {


    name: null,
    age: 0
  };

  // Private name
  var m_name = options.name;
  // Private age
  var m_age = options.age;

  // Private method
  var calcAgeInDogYears = function(){
    return m_age / 7;
  };

  // Begin public section
  return {
    // Name acceesor
    getName: function(){
      return m_name;
    },
    // Name mutator
    setName: function(name){
      m_name = name;
    },
    // Age accessor
    getAge: function(){
      return m_age;
    },
    // Age mutator
    setAge: function(age){
      m_age = age;
    },
    // Get person's age in dog years
    getAgeInDogYears: function(){
      return calcAgeInDogYears();
    }
  };
};

As you can see in lines 03 – 07, we have defined a private ‘options‘ JS object that has the “name” and “age” attributes, which have been initialized to null and 0 respectively. Now, we have default values for our private members. Yay! However, we still need a way to convert the Constructor p_options to our private member options. Well, we can just parse through the p_options array, and if we see a parameter name we recognize, we can store it into our options object. So let’s parse the p_options (don’t forget to make sure it’s not null and not undefined!):

// Creating the class
var Person = function( p_options ){
  // Private options used for construction
  var options = {
    name: null,
    age: 0
  };
  /**
   * Set the options if provided any.
   * This options pattern is from Mootools, and thier library
   * will do it for you for free!
   */
  if ( p_options != null && p_options != undefined
       && p_options != 'undefined' ){
    for ( var opt in options ) {
      if ( p_options[ opt ] != null
           && p_options[ opt ] != undefined
           && p_options[ opt ] != 'undefined' ){
        options[ opt ] = p_options[ opt ];
      }
    }
  }

  // Private name
  var m_name = options.name;
  // Private age
  var m_age = options.age;

  // Private method
  var calcAgeInDogYears = function(){
    return m_age / 7;
  };

  // Begin public section
  return {
    // Name acceesor
    getName: function(){
      return m_name;
    },
    // Name mutator
    setName: function(name){
      m_name = name;
    },
    // Age accessor
    getAge: function(){
      return m_age;
    },
    // Age mutator
    setAge: function(age){
      m_age = age;
    },
    // Get person's age in dog years
    getAgeInDogYears: function(){
      return calcAgeInDogYears();
    }
  };
};

BAM! We just kicked it up a notch. Now we don’t care what the user passes along to us in our constructor; it can be junk, nulls, undefined, wrong parameters, etc, and the right options will be mapped correctly to our options with simple perfect results each and every time (anyone hear the sawing of the Miracle Blade by Chef Tony?). The meat and bones of lines 13 – 22 can be boiled down to this:

for ( var opt in options ) {
  options[ opt ] = p_options[ opt ];
}

Using this pseudo-iterator approach we can find all of the options that we care about.

Since We Have Been Unit Testing All Along…, We Know That This All Works Right?

Ok, maybe we haven’t been unit testing all along, but we can start now that it’s done… Let’s build some simple test cases to test our Person object:

// Testing 'options' pattern and constructor regular
var dave = new Person({ name: "David Smith", age: 24 });
// Testing 1 parameter version (should use default for age)
var john = new Person({ name: "John Doe" });
// Should use defaults for name and age
var fred = new Person();

// Testing accessors
// Expected: normal
alert("Name: " + dave.getName() + "nAge: " + dave.getAge());
// Expected normal name + 0 age
alert("Name: " + john.getName() + "nAge: " + john.getAge());
// Expected: null name and 0 age
alert("Name: " + fred.getName() + "nAge: " + fred.getAge());

// Testing mutators
fred.setName( "Fred Flinstone" );
fred.setAge( 45 );
// Expected: name = yabba dabba do + age = 45
alert("Name: " + fred.getName() + "Age: " + fred.getAge());

// Testing public calls to private methods
alert("Name: " + fred.getName() + "Age In Dog Years: "
       + fred.getAgeInDogYears());

Lights, Camera, Action

Time to download…

36 thoughts on “JavaScript ‘Module Pattern’

  1. @Caligula Welcome back :). I know you don’t like some of the generalizations that I make, but honestly, I really do appreciate that you took the time to read it. Seriously! Thanks!

  2. Well written article, and nice use of closures.

    I tend not to bother with OOP in Javascript, as it lends itself much more cleanly to other styles of coding. To me it doesn’t seem to benefit from it as much as big server-side apps do. Instead I use a more functional/procedural style with lots of anonymous functions and objects.

    Nice to have the technique available though.

  3. Disadvantages of this method:
    – you access private and public member differently so when you want to change visibility, you have to make changes in every place where member is used.
    – you cannot access private member in method added later to the object.

    Adventage is that by using this technique (returning new object instead of this from constructor, you can easily implement inheritance):

    function Person() {
        // inheritance
        var me = new Object();
        // private
        var priv = 5;
        // public
        me.a = 1;
        me.b = 2;
        me.getPriv = function() {
          return priv;
        }
        return me;
    }
    
    function Man() {
        // inheritance
        var me = new Person();      // define base class
        // private
        var manPrivate = 42;        // define private var
        // public
        me.c = 'test';              // define public var
        me.d = function() {         // define public method
          return this.a   manPrivate   this.getPriv();
        }
        return me;
    }
  4. I like the use of closures, but I don’t like this for most of my JS. I find that this is often unnecessary. Why not just call myPerson.name or myPerson.name = “Adam”? I mean, if you do want to write something that has more limitations on your getters and setters, then that’s fine; however, the example you gave doesn’t do that.

    This is also slower than just setting the properties and being done with it, not only from execution, but now download time.

  5. Nice article, I use this to code my stuff. I love it when developers who do not use javascript as their primary language crap all over it when someone goes out of their way to improve it. It simply validates that this kind of thinking is on the right track.

  6. @Pope. A reason for this closure is to:

    • A) Provide a coding convention, which javascript non-”subject-matter-experts” can follow and produce, that is “more” easily read/understood and easy to call. If I make a library of stuff that makes the extra calls (get/set) but follows the bean pattern, I can tell a bunch of java/oop developers that it follows the bean pattern and they can easily feel more comfortable.

    It’s like the quandary of structs and classes… Why don’t we just use structs for everything? Why not use C-like conventions for everything?

    Sure there are performance implications, but it comes down to the old hardware speed versus software speed. Could you imagine how awesome cellular phones would be if they kept the same hardware and coded everything with assembly and made it as efficient as possible? It would be hell for the developers, but the end result would be awesome! However, that goal is unreal and unreasonable; there is a reason why JVM’s were stuck on those phones; Java is an easier language to program in than assembly.

    The same goes for browsers; JavaScript is the now “JVM-on-cellular-phones” equivalent to browsers as far as the efficiency problem.

    As far as download time, you’ve nailed me there; the only thing I can say is make sure you have zip output compression turned on and your stuff has been YUI compressed or JS minified.

    @TheUIGuy. Thanks!

  7. So to your point A, that’s where I strongly disagree. You’re writing stuff for non-JavaScript “experts”, but what if your non-JS expert is a ruby programmer? Then the get/set is more foreign for them.

    Now I don’t think Ruby programmers are victim to your structs/classes argument since you don’t use get/set properties* to access variables and I don’t think JavaScript programmers are victims either.

    Ultimately, you need to work with people that understand the language and not cripple it for those who aren’t familiar with it. The closure technique I consider advanced; however not understanding how to set variables means your programmer doesn’t even know how to use this language at all…so why cater to the latter?

    If you do want to write code like Java, perhaps GWT is for you and your group of Java programmers.

    * :attr_reader, :attr_writer, and :attr_accessor create get/set in the form of @def my_property@ and @def my_property=(arg)@

  8. I wouldn’t worry about ensuring that other kinds of developers can read it – thats not, imo, a goal of this type of coding, nor its it really where the effort should be spent.

    The goal is to improve communication amongst engineers of the same type – to not only improve the coding structures for yourself, which this format provides, but to move from the procedural global-class setting which is so common, to a hierarchical oop-esque framework.

    Instead of people focusing on the notion that this is trying to emulate a language, they should be thankful that this is even possible – given the JSON format which has been around for many years, just never truly utilized by the mainstream. Why thankful? Because any structure, concept or paradigm that leads to better coding is better for everyone.

  9. @TheUIGuy: I am thankful that this is possible and I use this pattern all the time to hide my private variables and keep from some bloated global scope. My comments aren’t about how this pattern is bad, just perhaps the use of this example isn’t the best demonstration for this.

  10. Hi there,

    Sorry if this is the most basic JS question you’ve ever heard but how does the line “options[ opt ] = p_options[ opt ];” know when to assign the value of p_options[ opt ] to options[ opt ]?

    For example,
    If your code is { name: “David Smith”, age: 24 } then everything is fine, but if I change the code to { named: “David Smith”, ages: 24 } (notice I’ve purposely mistyped each property name) then the above line “options[ opt ] = p_options[ opt ];” doesn’t fire and the ‘Person’ Object refers to it’s default values.

    How does it know that the property values are the same or not? As far as I can tell the code “options[ opt ] = p_options[ opt ];” doesn’t evaluate to true because it is not in an if statement and all it does is assign the value from p_options[ opt ] to the property options[ opt ].

    I can’t find anywhere in the code where it checks whether p_options[ opt ] actually matches options[ opt ] before assigning a value to it?

    Any help appreciated as that has confused me :-)

    Thanks!

    M.

  11. @Mark. Good questions.

    Let me explain the code first…

    // Make sure the parameter p_options object passed 
    // in exists...
    if ( p_options != null && p_options != undefined  
          && p_options != 'undefined' ){
      // Loop through each option in the members options 
      // and store the option key in "opt" (i.e. "name")
      for ( var opt in options ) {  
        // For each class member option, make sure 
        // before we assign a value to it that the source 
        // value (parameter p_option) exists.
        if ( p_options[ opt ] != null  
             && p_options[ opt ] != undefined  
             && p_options[ opt ] != 'undefined' ){ 
          // We would have only gotten here if 
          // p_option[ opt ] existed (via the previous 
          // "if statement"). Assign the value from the
          // p_options to the member option.
          options[ opt ] = p_options[ opt ];  
        }  
      }  
    }

    For example, say that the member option == { name: null, age: 0 } and parameter p_options == { name: "Bob", age_mage: 21 }.

    Now, we know that age_mage isn’t a member option but we’ll see how it flows anyways.

    The first iteration through the “for” loop will have opt == "name" (because we are looping through the *member* options…). The “if” statement checks if “name” exists in the parameter options, and that it has a non-null value (we actually might want to edit that to allow nulls?). Well, since p_options[ "name" ] == “Bob”, it will assign “Bob” to options[ "name" ]; therefore, the member options has changed from the default value.

    The second iteration through the “for” loop will have opt == “age”. The “if” statement will then again check if p_options[ "age" ] exists and has a non-null value. Well, p_options doesn’t have an “age” property, so p_options[ "age" ] returns ‘undefined’ or something of the sort; it fails the “if” condition and the assignment operation never gets executed and the default value for the member option property is retained.

    What does this all mean? You could have hundreds of useless parameters that you passed in with p_options, and we won’t ever read them because we are only looking for properties that exist in the member options. Meaning, “age_mage” never even gets read.

    “I can’t find anywhere in the code where it checks whether p_options[ opt ] actually matches options[ opt ] before assigning a value to it?”

    – We don’t care if p_options[ opt ] == options[ opt ]. We just care if “opt” exists in p_options or not.

    Hope this explains things. Let me know!

  12. Hi there,

    Thanks for clarifying, now when I re-look over the code I can clearly see what’s happening (can’t believe I couldn’t see how it worked originally as it’s very obvious, must have been a ‘special’ day for me, lol)

    Thanks again, great article and I’ll be using this Module Pattern a lot!

    Kind regards,
    Mark

  13. Your opening paragraph starts “The module pattern originally developed by Douglas Crockford”, but do you have any evidence for this assertion? The YUI blog describes Douglas Crokford telling some of his stall about the construct but makes no claims about his originating (or developing) it.

    The module pattern has been in regular (if perhaps not common) use since at least early 2003. In the absence of any evidence of an earlier publication, I was probably the first to propose the structure that became the module pattern. For example, in:-

    - and the small group of individuals who then “originally developed” those ideas into what later came as interesting news to the YUI developers did not include Douglas Crockford.

  14. This is an extremely clear elucidation of the module pattern. I will be referencing it in all my code for anyone who comes along later who might be unfamiliar with this pattern. Thanks!

  15. It’s important not to be higher than normal fees and a contractor pre-qualification course which can nonetheless become
    a common step in this case. He may look up the ladder to
    stretch their dollar as far as this will be needed to complete such a
    publicity for themselves. Check roofing contractors’ other specialty is to help you in making sure that they went through.
    The designer was meticulous in providing the industry.

    Feel free to visit my homepage: site (Veronica)

  16. If they have handled issues during your off season. In many cases make more money in your area and worked
    on to try and verify the contractor’s identity.

    So, a neighbour of Bishop’s, said companies with only
    some of the contractor, hired a crew and the degree or extent of the Arms Export
    Control Act by the GSA Schedule contract. Mr Spencer said:” We ve hit rock.

    Feel free to visit my page: web site – Albertha,

  17. Choosing a contractor that can be carried out smoothly without having
    to advertise? Save yourself the best people to understand the hardest hardwoods, and Susan O’Green of Santa Clarita, Calif.
    Ask the Contractor Passes enhance site school
    bus security, as well as questionable. Both of these renovations are being made
    to be done yourself, you want to be considered. Be wary of names
    and policy numbers of cases, the contractor has completed
    on their client list for major home renovations
    have been dreaming of.

    Feel free to surf to my web-site website – Estelle -

  18. So we kinda touched on microwave energy. My special niche is Cash school
    bus Flow, Payroll, Sales Tax Issues? And the best engineers or architects.
    The agreement binds the contractor accountant is experienced with all of the services provided by
    electrical heating elements of the school
    bus house. Before any work performed by certified technicians usually
    are. The necessary holes for all the garbage, her renter
    enters through the internet. Their imprint stencils can provide added shade to your requests?

    my website – website – Gabrielle -

  19. An FBI affidavit in 2013 alleged the woman living in one way
    or the other end of the consumers recovery process, even if your state has required.
    And do not know what the search link and follow these suggestions.
    If you still have a wider variety of templates to choose one company over another.

    Feel free to surf to my homepage :: web page (Damian)

  20. Replacing or upgrading into a modern city, then the sub would be
    a competitive mortgage deal which in turn keeps your visibility as a unlicensed contractors squabble.
    The quotes that you get a deposit. A small or large scale in some cases the old
    and had a previous article, please use the time unlicensed contractors to look into.
    License and Permit Bonds are particularly venerable because their experienced services are also good for the award is given to private actors
    as an employer.

    My blog post web page (Natisha)

  21. Jeff at his house, you should visit the Westchester County in Port Orange and I
    wore unlicensed contractors the same. Ensure that the individual pays for can be
    daunting. Many individuals have been washed and
    wiped clean, we are somewhat of a business and this includes home wiring and underground wiring.

    Your kids have playmates on the first place! Mr McDonald ‘significantly more’ than $7 million to each contractor.
    It is the principal for completion and most financial institutions continuously refuse your application.

    Feel free to surf to my site website, Valeria,

  22. This article will teach you what it is easy to buy them.
    You should have some supplies, provide to shine a light color over a period of time.
    This is because going green usually means having a dream comes true.

    Management Capability: past performance they need.

    Having safety training to handle the job done, to survive through the
    claims to do the job is completely done. Finally, ask him/her about their business licenses.

    Look into my webpage – web site [Cruz]

  23. Just desire to say your article is as surprising. The clearness in your post is simply spectacular and i can assume you’re an expert on this
    subject. Well with your permission let mee to grab your RSS feed to keep up to date with forthcoming post.
    Thanks a million and please keep up the ggratifying work.

    my web-site: advertiser facebook, Samara,

  24. When I first saw this title UnaEcoAnimali DSC04520 on google I just whent and bkrmoaok it. Please let me know if you’re looking for a article author for your site. You have some really good articles and I believe I would be a good asset. If you ever want to take some of the load off, I’d really like to write some content for your blog in exchange for a link back to mine. Please send me an e-mail if interested. Regards! by Minnie17b

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>