JavaScript for C# developers: writing a library (part 1)

From comments I received when I wrote my recent article over on my DevExpress ctodx blog, it seems there’s a need for people to understand how to write reusable code in the form of a library in JavaScript, and not fall into those nicely shaped C# potholes along the way. So I thought, let’s have a go. (Update: I’ve made a couple of corrections to point out the files this code appears in.)

Some ground rules first. The first is that I’m going to use jQuery. Although jQuery is perhaps best known as being a DOM manipulator library, I think it’s now almost de rigueur amongst people who use the Microsoft ASP.NET stack for writing web applications. My initial code won’t be doing much DOM manipulation, but I shall use jQuery nevertheless. The second is that I’m going to be using modern JavaScript best practices (no globals, use of closures, getting the code to pass JSLint on its default settings, thinking about performance, etc). The third is that, at the start, it will seem that I’m going overboard with single JS files, one per object, with all the performance problems that might entail in a “real” web site, but I shall be addressing that later on.

Onwards.

The first problem to solve is that of my global footprint. If you’ve read any of my writing about JavaScript in the past (say from my chapter on JavaScript in Professional DevExpress ASP.NET Controls), I’ve espoused minimizing the number of global variables you create. There are many reasons for this, many standard, many obvious, but this time in writing my library I want to reduce it to zero. Since my library has to be visible, er, globally, how should I do this? Well, I shall piggyback on another global object: the jQuery function. Yes, this is cheating to a certain extent (I’ll be creating a globally available object in a global object, essentially), but it’s accepted practice when you use jQuery.

Here’s the minimal code you need to write to create such an object:

  $.jmbLibrary = {};

The $ function (functions are objects, remember, so all I’m doing is adding a property) is a synonym for the jQuery function, and all I’ve done is to create an empty object called jmbLibrary as a property of that function. Seems pretty easy, until you realize that the $ identifier may clash with other libraries and jQuery has a way of disabling that identifier altogether (call jQuery.noConflict(false);). I am no longer writing code for a particular page, I’m writing reusable code that could be used everywhere, even on projects that I have no control over. However, the $ is such a nifty shorthand; surely there’s a way to keep it and not have clashes?

Enter a closure. (Admit it: you knew a closure was going to come up sooner or later.)

(function ($) {

  $.jmbLibrary = {};

})(jQuery);

Whoa. What’s going on here? In essence, I’m declaring an anonymous function, not assigning it to any variable, and executing it immediately passing in jQuery as its only parameter. But inside the function body that parameter is known as... our old friend $. (Well, OK, a new friend, but with the same name and the the same functionality.) Throughout that function scope, the jQuery function will be known as $, no matter what happens outside that function.

The reason for the function declaration being enclosed in parentheses is to ensure that the interpreter doesn’t try and parse this code as the start of a named function object like this: function foo() {...}.  We use the parentheses to avoid that confusion.

So now I have the very basic code for my library: a globally accessible object that doesn’t appear in the global scope. I’ve added this minimal code to a JavaScript file called jmbLibrary.js. Let’s add some real functionality to my library now.

The first library object I’m going to add to my library is an encapsulation of cookies. (The web versions, not the sugary crumbly things you bake in an oven; pay attention, people.) I’m going to create a cookie library object within my jmbLibrary object and it will have three methods: add, read, and remove (delete is a reserved word in JavaScript so I can’t use that too easily) to encapsulate the three main operations you can perform on a cookie. So I start off with this code in a file called jmbCookie.js:

(function ($) {

  var $j = $.jmbLibrary;
  var $jc = $j.cookie = {};

})(jQuery);

Same kind of code we’ve just become used to: an anonymous function, not saved but immediately executed in order to provide a closure inside which $ refers to jQuery. I’m declaring two local variables within this closure, one called $j, to refer to the library as a whole, and one called $jc to refer to a new empty object called cookie I’m creating in jmbLibrary. Yes, you guessed it, I like these shorthand names.

Note that our HTML file (which I’m not showing yet) will have to have the following script elements in the head element (I’ve created a Scripts folder for all these JavaScript files):

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">script>
  <script src="Scripts/jmbLibrary.js" type="text/javascript">script>
  <script src="Scripts/jmbCookie.js" type="text/javascript">script>

Next time, we’ll take a look at the actual cookie code. Stay tuned.

Album cover for The Best of BlondieNow playing:
Blondie - Call Me {Theme from American Gigolo}
(from The Best of Blondie)

Loading similar posts...   Loading links to posts on similar topics...

2 Responses

 avatar
#1 dumbledad said...
01-Sep-11 8:18 AM

Great start :-)

One question. I don't understand how auto-complete etc will pick up jQuery functions purely from passing jQuery as $ into the closure. It is only in the html page that the jQuery library is loaded before yours, so how does the IDE know what to make of the jQuery variable in your library jmbLibrary.js and jmbCookie.js files?

julian m bucknall avatar
#2 julian m bucknall said...
05-Sep-11 9:43 AM

dumbledad: Search me. In my experience, such IDE niceties as auto-complete and the like just don't do well once you have indirection as I've used.

Cheers, Julian

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response