CoreJS And Namespace

Todays post is going to introduce the file that provides the core functionality for my personal JavaScript Framework. I have already introduced several parts of the file, such as type detection and cookie management. You can view the code @

The first thing youll probably notice is that I comment everything. This is the most important part of programming, and often overlooked in Web Applications. You almost can not have enough comments in any given file. In my case, I write so much code and work on so many different projects on a daily basis that without comments, I would be lost. But beyond that, if I wrote a file (of any reasonable length) 4 months ago and revisit it now, I am probably going to have to reacquaint myself with what it is doing (and most likely improve it a little). Figuring out what is going is exponentially faster when you comment your code. Its best to comment: all functions, large blocks of code, anything that might be confusing, and all hacks.

Now, back to Core.js. What is does this all do? First, you will see a section that sets up some W3C standard constants, which should be attached to the document. These constants will be used anytime you want to compare the nodeType of a DOMElement. Older browsers and IE do not define these by default, so this block of code fixes that. Note that I do not use browser detection to figure this out, but instead see if the variables are defined in the document namespace. Always try not to use browser detection if you can.

 *  W3C DOM Level 2 standard node types; for older browsers and IE
if (null == document.ELEMENT_NODE) {
	document.ELEMENT_NODE                   = 1;
	document.ATTRIBUTE_NODE                 = 2;
	document.TEXT_NODE                      = 3;
	document.CDATA_SECTION_NODE             = 4;
	document.ENTITY_REFERENCE_NODE          = 5;
	document.ENTITY_NODE                    = 6;
	document.COMMENT_NODE                   = 8;
	document.DOCUMENT_NODE                  = 9;
	document.DOCUMENT_TYPE_NODE             = 10;
	document.DOCUMENT_FRAGMENT_NODE         = 11;
	document.NOTATION_NODE                  = 12;

An example of how you might use this is:

var isTextNode = function(node) {
	return document.TEXT_NODE == node.nodeType;

So, if you pass a DOMElement into the function isTextNode(), it will return true if the node is a text node.

The next block of code defines the Core Object and namespace. I say namespace, because the Core Object will be the global Object that the Framework will be attached to. I use the module pattern as coined by Douglas Crockford to create my Core Object. This gives me the freedom to create private-like variables: debugLevel and clientInitFunc. Debug level is a variable I use to differentiate between production and development messaging. clientInitFunc also uses the module pattern, creating the template that will evaluate the users browser and OS. This is also a logical place to attach cookie management Functions. Here are some references for these methods:

Again, let me reiterate, "DO NOT USE BROWSER DETECTION, UNLESS ABSOLUTELY NECESSARY". That said, the two browsers you might have to detect most often are IE and Opera, so I have two shortcut methods: isIE and isOpera that compares against the Core.browser variable.

The next statement returns the constants and methods attached directly to the Core namespace. These include additional namespace variables: Biz, Debug, Client, Widget, and Util. Each of these have been commented to explain what to use them for. I frequently use Core.Client and therefore have attached the Client Object created during the initialization of the Core Object to Core.Client for ease of access.

The next two Functions are helper methods that did not belong in the global namespace, nor any other namespace, so I have attached them to Core. deepCopy copies an Object or Array and all of its member Objects and Arrays until all children have been copied. I need this from time-to-time to prevent Objects from being passed by reference, when I do not want a Function to modify the passed element. getImage is a short-cut method to create an Image instance and then attach the URI src to the image Object. This allows pre-caching of images and simplifies code.

getDebugLevel is used to retrieve the debugLevel variable. I have designed it this way, because I want to ensure that I (or a hacker) can never update the debug level directly once the script is loaded into the page. Lastly, the init function initializes some internal Debug variables and initializes the Core.Client Object.

Now, the emptyFunction Function and Class Object are copies of similar elements in the Prototype Framework. They probably should not be in the global namespace, but i have not had a good enough reason to move them yet. emptyFunction is handy, because it allows you to supply a generic do-nothing method. The Class Object, can be used to create Prototype Objects, but is something I try to stay away from. I have only one instance in the Form Validator that benefited from this design pattern, and so it remains. Also, the amount of code is negligible and some people may prefer to build Prototype Objects.

The file closes with all the type detection functions. These are described in detail for the Type Detection article.

Although, short and sweet, this file has some complex ideas and may take a little getting used to. Please let me know your thoughts and any possible improvements, especially with the deepCopy method.