Eric Miraglia (@miraglia) is an engineering manager for the YUI project at Yahoo. Eric has been at Yahoo since 2003, working on projects ranging from Yahoo Sports to YUI. For the past several years, Eric and his colleagues on the YUI team have worked to establish YUI as the foundation for Yahoo’s frontend engineering work while open-sourcing the project and sharing it with the world under a liberal BSD license. Eric is an editor and frequent contributor to YUIBlog; his personal blog is at ericmiraglia.com. Prior to working at Yahoo, Eric taught writing at Stanford and elsewhere and led frontend engineering teams at several startups.
Global variables are evil. Within YUI, we use only two globals: YAHOO and YAHOO_config. Everthing in YUI makes use of members within the YAHOO object hierarchy or variables that are scoped to such a member. We advise that you exercise similar discipline in your own applications, too.
Douglas Crockford has been teaching a useful singleton pattern for achieving this discipline, and I thought his pattern might be of interest to those of you building on top of YUI. Douglas calls this the “module pattern.” Here’s how it works:
1. Create a namespace object: If you’re using YUI, you can use the YAHOO.namespace() method:
YAHOO.namespace("myProject");
This assigns an empty object myProject as a member of YAHOO (but doesn’t overwrite myProject if it already exists). Now we can begin adding members to YAHOO.myProject.
2. Assign the return value of an anonymous function to your namespace object:
YAHOO.myProject.myModule = function () {
return {
myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty.",
myPublicMethod: function () {
YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");
}
};
}(); // the parens here cause the anonymous function to execute and return
Note the very last line with the closing curly brace and then the parentheses () — this notation causes the anonymous function to execute immediately, returning the object containing myPublicProperty and myPublicMethod. As soon as the anonymous function returns, that returned object is addressable as YAHOO.myProject.myModule.
3. Add “private” methods and variables in the anonymous function prior to the return statement. So far, the above code hasn’t bought us any more than we could have gotten by assigning myPublicProperty and myPublicMethod directly to YAHOO.myProject.myModule. But the pattern does provide added utility when we place code before the return statement:
YAHOO.myProject.myModule = function () {
//"private" variables:
var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";
//"private" method:
var myPrivateMethod = function () {
YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");
}
return {
myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty.",
myPublicMethod: function () {
YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");
//Within myProject, I can access "private" vars and methods:
YAHOO.log(myPrivateVar);
YAHOO.log(myPrivateMethod());
//The native scope of myPublicMethod is myProject; we can
//access public members using "this":
YAHOO.log(this.myPublicProperty);
}
};
}(); // the parens here cause the anonymous function to execute and return
In the codeblock above, we’re returning from an anonymous function an object with two members. These members are addressable from within YAHOO.myProject.myModule as this.myPublicProperty and this.myPublicMethod respectively. From outside of YAHOO.myProject.myModule, these public members are addressable as YAHOO.myProject.myModule.myPublicProperty and YAHOO.myProject.myModule.myPublicMethod.
The private variables myPrivateProperty and myPrivateMethod can only be accessed from within the anonymous function itself or from within a member of the returned object. They are preserved, despite the immediate execution and termination of the anonymous function, through the power of closure — the principle by which variables local to a function are retained after the function has returned. As long as YAHOO.myProject.myModule needs them, our two private variables will not be destroyed.
4. Do something useful with the pattern. Let’s look at a common use case for the module pattern. Suppose you have a list, some of whose list items should be draggable. The draggable items have the CSS class draggable applied to them.
<!--This script file includes all of the YUI utilities:-->
<script type="text/javascript" src="http://yui.yahooapis.com/2.2.2/build/utilities/utilities.js"></script>
<ul id="myList">
<li class="draggable">Item one.</li>
<li>Item two.</li> <!--item two won't be draggable-->
<li class="draggable">Item three.</li>
</ul>
<script>
YAHOO.namespace("myProject");
YAHOO.myProject.myModule = function () {
//private shorthand references to YUI utilities:
var yue = YAHOO.util.Event,
yud = YAHOO.util.Dom;
//private method:
var getListItems = function () {
//note that we can use other private variables here, including
//our "yud" shorthand to YAHOO.util.Dom:
var elList = yud.get("myList");
var aListItems = yud.getElementsByClassName(
"draggable", //get only items with css class "draggable"
"li", //only return list items
elList //restrict search to children of this element
);
return aListItems;
};
//the returned object here will become YAHOO.myProject.myModule:
return {
aDragObjects: [], //a publicly accessible place to store our DD objects
init: function () {
//we'll defer making list items draggable until the DOM is fully loaded:
yue.onDOMReady(this.makeLIsDraggable, this, true);
},
makeLIsDraggable: function () {
var aListItems = getListItems(); //these are the elements we'll make draggable
for (var i=0, j=aListItems.length; i<j; i++) {
this.aDragObjects.push(new YAHOO.util.DD(aListItems[i]));
}
}
};
}(); // the parens here cause the anonymous function to execute and return
//The above code has already executed, so we can access the init
//method immediately:
YAHOO.myProject.myModule.init();
</script>
This example is a simple one, and it’s deliberately verbose — if this was all we were doing, we could doubtless write it in a more compact way. However, this pattern scales well as the project becomes more complex and as its API grows. It stays out of the global namespace, provides publicly addressable API methods, and supports protected or “private” data and methods along the way.
October 26, 2009 at 9:31 am
Thanks a lot for the article Eric! Though it has been published way long back, it is being referred by many young modern JavaScript developers even now.
October 26, 2009 at 6:51 pm
Gr8 Article Eric!
November 16, 2009 at 1:22 pm
[...] A common way to share functionality among different YUI instances is to use the YUI namespace when assigning the function. If you do not recognize the structure of the above function definition you may find out more be reading about the module pattern. [...]
November 20, 2009 at 4:06 am
[...] Global scope: Avoid using global scope where you can. For example, nesting functions. R obert later points to the Yahoo! module pattern. [...]
November 22, 2009 at 1:06 pm
[...] Module pattern – the most flexible way to do namespaces for javascript. [...]
November 28, 2009 at 11:14 am
I’ve been using the module pattern ever since I saw Douglas Crockford’s video explaining it. But I do it slightly differently. Instead of placing the return statement above the definitions of public functions, I place it at the end of the module and just reference the functions I want to make public, like this:
return {
init: init,
calculate: calculate,
…
}
December 28, 2009 at 5:47 am
[...] This is a great article by Eric Miraglia posted on Y!UI Blog. [...]
January 4, 2010 at 5:02 pm
[...] celui de JavaScript, mais l’autre de l’excellente bibliothèque YUI, qui vise le HTML (même s’il n’a pas [...]
January 26, 2010 at 12:43 pm
[...] example code below is adopted from (http://yuiblog.com/blog/2007/06/12/module-pattern/): // create a namespace YAHOO.namespace("myProject"); // Assign the return value [...]
April 6, 2010 at 7:25 pm
[...] The Module Pattern was a pattern coined by Douglas Crockford. If you don’t know who that is… his website is http://www.crockford.com/. He maintains the JSON standard and writes fancy tools like JSMin and JSLint and is currently employed at Yahoo! as a Senior JavaScript Architect. A quick primer for the module pattern is on YUI Blog. [...]
April 8, 2010 at 7:13 pm
[...] in Mootools, but decided to refactor the code to not use the Class object. Instead, I followed the YUI module pattern that uses closure which feels more natural since, with private variables in the outer function, I [...]
April 23, 2010 at 4:40 pm
@Larry
That variation was already mentioned by Rowan, and as Burke points out, is often referred to as the “revealing module pattern.”
July 9, 2010 at 12:21 am
[...] of the best practices on the web is Doug Crockford’s “module pattern,” which is a coding pattern for writing unobtrusive components that avoid stepping on the [...]
August 28, 2010 at 3:51 pm
[...] As a developer, you definitely don’t want to jump in unprepared. You want to have a strategy and an understanding of the surrounding and underlying architecture. From a JavaScript standpoint, this typically means agreeing on a standard approach to coding, with many teams choosing to use the Module Pattern. [...]
September 19, 2010 at 2:53 am
I had a ‘lightbulb moment’ reading this article and a few more reading the comments. Thanks guys n girls.
December 14, 2010 at 3:33 pm
I apologize for the nit-picking, but in the code for section 3…
myPublicProperty: “I’m accessible as YAHOO.myProject.myModule.myPublicProperty.”
… Needs a comma at the end
YAHOO.log(myPrivateMethod());
… myPrivateMethod has to return a string for this to work, otherwise this generates an ‘undefined’.
I guess in the three years since this was written, no one else must’ve tried to copy/paste it. =) Thanks, I really like this, it’s helping me out a lot!
December 16, 2010 at 10:47 am
[...] code and sloppy code can be mixed in the same file. This second form works very well with the Module Pattern and its many variations. The second form is preferred because it avoids the concatenation [...]
December 16, 2010 at 9:45 pm
[...] code and sloppy code can be mixed in the same file. This second form works very well with the Module Pattern and its many variations. The second form is preferred because it avoids the concatenation [...]
December 21, 2010 at 9:09 am
[...] what would best suite our needs. After a bit of research we decided to go with the self executing module pattern. For example we have something like this (edited for [...]
December 30, 2010 at 5:44 pm
Saul – didn’t you mean “it needs a semicolon” ?
January 11, 2011 at 12:50 am
@Kim – no, I did mean a comma. A semi-colon would break the array. I’m not sure why exactly I said that, because I’m looking at the code and it quite clearly has a comma. Must not have had enough caffeine that day….
January 28, 2011 at 5:37 am
[...] framework de l’exemple est sensé être conforme au design pattern « module » et l’ensemble de son code est donc accessible sous forme d’une variable globale. Dans les [...]
February 26, 2011 at 1:08 am
Thanks a lot for the article Eric! Though it has been published way long back, it is being referred by many young modern JavaScript developers even now.
March 18, 2011 at 5:45 pm
@Monin – Can you please provide a more detailed explanation of your modification to allow instances?
March 22, 2011 at 3:12 pm
[...] simple overview of the module pattern, which has been well-known since Eric Miraglia (of YUI) first blogged about it three years ago. If you're already familiar with the module pattern, feel free to skip ahead [...]
March 31, 2011 at 3:14 am
Nice tutorial.
Indeed, it’s the 1st time i create JavaScipt module by using YUI. But, i think your guides’re clear & easy to understand. Thank for sharing
Jimmy
April 6, 2011 at 10:51 pm
[...] June Framework was inspired by the Core library and uses the Module design pattern. For those using MS Visual Studio 2008, you’ll love the documentation that comes with the June [...]