The javaScript module object literal pattern
So there are many patterns and standards when it comes to javaScript modules these days. Just when it comes to making them the tired yet true way in a es5 spec javaScript kind of way things can quickly spiral down in to a major rabbit hole when it comes to the various patterns, and standards with old school style javaScript. Then there is of course the new ways to go about making javaScript modules in modern javaScript specs when it comes to using import and export.
However if you are new to javaScript module design, you have to start somewhere, and maybe a good starting point would be to just start playing around with plain old object literals as a javaScript module pattern in client side javaScript. This might not be the best way to go about making modules in javaScript, but it sure is a good first step in the right direction if you are not sure where to start. Also in some cases the pattern will still work okay in some situations in which I am making a client side module in which it is okay to make everything public. Also I can still wrap things up into an IIFE when it comes to making a single property value for a public key of the main object literal that will compose such a module.
1 - The basics of a javaScript Object literal module pattern
When I was first starting out with javaScript many years ago I am sure that I was writing simple javaScript code examples that would just be a bunch of global variables, and methods where I am mutating those global variables. This kind of approach to things is something that I tend to avoid doing, but for now lets just assume that we are starting out with some code like that.
|
|
Although this might not be much so far, there is a few things that I would all ready do differently here these days. However the first thing that comes to mind would be to pull this code into some kind of module pattern. One way to go about making this code a little ore modular would be to turn this code that is just littered around in the global name space into just a single global object in the forum of an object literal.
|
|
So now I have the same code, working more or less the same way, but in an object literal module form. This is then one way to go about taking all these things that would otherwise be polluting the global name space just be a single global.
2 - Making a module more in line with functional programing using the object literal module pattern
I will not be getting into function programing and pure functions in detail here as that would be off topic. However I would say that taking code in a more functional direction is generally a good idea. It will result in code that is easier to follow and debug. In addition I have found that I do not like the idea of having a state object located in a module itself, but as an object that is outside of the module, and just use the module to create new state objects rather than directly mutating them.
The basic point module that I made in the last section could be changed up just a little to create something that does more or less the same thing, but in a way in which it is more functional. The first thing to do is to pull the x and y variables that store the current state of something out of the module, and instead just have a method that will create a state object with those properties. I would then make the point object an argument that is passed to my move method rather than mutating these values that are part of the module itself. The next thing to do is to make the move method a pure function by making it so that it will return a new point object rather than directly mutating the source object that I pass to it as an argument.
|
|
So then this would be a better example of how I would make a javaScript module with the object literal pattern these days. I do not always follow a functional way of programing though, but generally I try to keep things going in that direction. As a project grows in size it just becomes more and more important to do so.
3 - Appending methods to an object literal rather than just doing everything when creating it in the first place
One more thing abut the object literal pattern is that sooner or later I find myself pulling methods out of the object literal that is used to create the object in the first place, and instead append methods to the object after it is created. So far there are not many reasons to do this, but as the module continues to grow, and if it does transition into another pattern I have found that doing this becomes more important.
|
|
4 - Using An IIFE for object properties
Some may argue that the main reason why not to use the object literal pattern is because everything will be public. As a result if one is in a situation in which there will be many private helper functions, and built in defaults that should not be public, one just has to make all of these things public. As such the result will be a polluted public API, with many methods, objects, and other features that should be private from the end user of the module.
However there are a number of ways of making some things private, without diverting from the pattern that much. For example I can use an IIFE when defining what a method should be for a public key of the object literal. Another option would be having a block of code that is an IIFE, and I pass the object literal as an argument to that IIFE, inside the body of the IIFE I can then have a whole bunch of private stuff.
It might be said that once you start doing this sort of thing it is not longer an object literal pattern, but now some other kind of pattern. In any case it is either still the object literal pattern, or a new kind of pattern that is just a little more advanced. that main point I would like to make in this section is if you are not sure of you want to go with the object literal pattern it is not that hard to break free from it and start to do something else as needed without changing things that much. When done in certain ways it will not even result in cod breaking changes.
4.1 - Basic IIFE example for a single method
I place of just having a function expression as the value to be assigned to a key of an object literal I have have a self executing function expression or IIFE and it will then be the return value of this IIFE that will be the value for the pubic key of the object literal. It is then the return value that will be a function expression, and this inner function expression will then have access to private stuff in the body of the IIFE that can not be access form outside of the IIFE.
One example of this would be a log once method in which I can have a private count variable inside the body of an IIFE, and then an inner function expression that is returned that looks at this private count variable to see of it should log a given message or not. In the event that the count variable is below a max count argument that default to one the given message will just log once. I count then have some additional arguments, including one to just reset the count, but not set it to any value I want.
|
|
4.2 - Passing the object literal as an argument to an IIFE, and appending to it
Another option is to have the object literal be a value that is passed to an IIFE as an argument for the IIFE. I can then append to the object literal with just what it is that I want to be pubic, while keeping everything else private. For example say I want to have some methods that can be used to create and work with a box object, but I only want to make a few methods public, and keep certain other things private. I can write an IIFE, pass a reference to the object literal module as an argument for this IIFE, and just append the public box methods.
|
|
5 - Breaking the object literal pattern
As a module continues to grow I might want to break the object literal pattern at some point. One reason why might be because I just want to have a main function that I call off of the main global of the module. If so it is not to hard to transition into that if I follow the object literal pattern a certain way where I am appending to the object. In that case I just need to make the object literal a function in place of just a plain old object, and preserve the properties of the old object pattern.
|
|
Another reason why I would want to break the pattern is to have some helper methods or additional objects or values of one kind or another private from the public API. One of the drawbacks of using the object literal pattern is that everything has to be public, and in some cases this is not always such a great thing. One way to help make a few things private would be the have a Immediately Invoked Function Expression or IIFE and then have the public API returned inside the body of this IIFE.
|
|
This kind of module pattern is often what I end up with when I keep working on a module for a while and keep anding things on. Sooner or later I want to write at least a few private internal helper methods that I do not need or what to be part of the public API. making use of an IIFE or some other module patter is just what ends up needed to happen often sooner or later. Still I would say that an object literal is a good starting point, and as things move forward it is not always to hard to transition into something else as log as I keep things structured in a certain way.
6 - Conclusion
So that is it for now when it comes to the object literal module pattern. The pattern is a great starting point when it comes to starting out with a module, but I do not have to work so much about having to start all over if I want to transition into another pattern. There is of course a whole lot more to write about when it comes to modules and javaScript of course. This post was meant to just be a starting point of sorts when it comes to making them in a client side javaScript environment.
One major project that I have made when it comes to the object literal pattern is my general utilizes module that I have made, and continue to expand now and then. In fact many of the methods and code examples are borrowed from that module, and I also add additional methods to it when working out examples for posts such as this.
In a nodejs environment a whole other pattern needs to be observed when it comes to making modules in that environment, and also there are many other pattens and more modern ways of making modules in a client side environment.