June 16th, 2009 § Comments Off on What isn’t in a name? § permalink
If you don’t already know, polluting the global variable pool is a bad, evil thing in JavaScript land. If you’re not concerned with overwriting existing code then at least think about protecting your code from being overwritten by keeping it in your own namespace. All you need to create a namespace in JavaScript is an object literal.
Say you’re tasked with incorporating a third-party widget into your home page. You drop in their
include but suddenly one of the scripts on your site breaks. You haven’t changed your code so you assume it’s the include causing trouble. However, a JSLint shows that their syntax checks out fine. Looking through your functions you narrow the misbehaving lines down to the following:
function findElement(el) {
return document.getElementById(el);
}
function updateNews(content) {
findElement('news').innerHTML=content;
}
That is some horrible code. Worse, that’s horrible code in the global pool. Cracking open the third-party include you see this:
updateNews = function(container,source,freq)
{
// Snip....
}
My, that function name looks awfully familiar. In fact, it’s the same as yours. That means your code and the third-party code are fighting in the global variable pool. What’s a clever programmer to do? Do what works in other languages, of course!
Time to carve out your own namespace
This is ridiculously easy if you understand what object literals are and how to self-invoke an anonymous function. Those terms both sound scarier than they are. You simply create an object literal to act as your namespace – which is a bucket for all your code – then use anonymous functions to assign functions into it. Keeping with the theme of being a polite player in the global pool also make sure your namespace is either brand new or extends any existing namespace.
var AY = AY || {}; //Don't overwrite existing namespaces
AY.News = function() //A 'News' bucket for all news-related tasks
{
//The 'var' forces the findElement method
//into the News scope, not global
var findElement = function(el)
{
return document.getElementById(el);
}
//Anything in the return becomes publicly accessible, yet
//is also able to access private methods and variables
return {
updateNews: function(content)
{
findElement('news').innerHTML = content;
}
}
}(); //Self-invoke to make this available immediately
AY.News.updateNews('Hai');
What’s happening here? Well instead of dropping all of your code into the global you can stash it in a single namespace. In my case I’ve named my namespace as AY
, after my name. I used all capital letters to signify that this is not a variable or method belonging to any other code. For news-related items I’ve created a News
bucket.
Inside of my News bucket there are a few things happening. I’ve decided that findElement
should be a private method in my namespace so by prepending it with the var =
I designate it as existing only inside the AY.News
namespace. Without a public accessor no outside code can run that method. My return passes an object literal which houses any public methods, in this case the updateNews
method. Because they are a part of my AY.News
namespace these public methods can access private methods, which is why the updateNews
code still works.
Finally, the closing parentheses cause the anonymous function to automatically run, or self-invoke. This action executes the function and, during its execution, hits the return which is what causes the return data to be assigned to AY.News
. The return is an object literal itself that contains a reference to the “private” updateNews
, which will execute the update.
That’s it! There’s no more to it. I’ll grant that for personal scripts this technique is not absolutely necessary but if you ever want your code to play nicely in another environment it’s a good practice and makes other programmers less hesitant to use your code. Comments regarding execution of this technique are more than welcome. This is my personal flavor and because of JavaScript’s flexibility I’m sure there are some other great techniques out there. Comment away!
Recommended reading:
2009-06-17: Reordered and cleaned up copy.
June 7th, 2009 § Comments Off on Yet another article about closures § permalink
…or when variables get too friendly and cause trouble
JavaScript is a functional language. Because of its functional nature you can do really fun things that may not be readily apparent. One of my favorite things about JavaScript is its implementation of closures, a function complete with its own private scope. Why would that ever be useful? It helps get around one of my least favorite things about JavaScript: scope. A closure is a function that, while it has access to globally-scoped items, has its own, bound local scope. You know those times when you only want a variable to apply to a certain event? No? How about an example?
I bet at first glance you’ll be able to tell me what this bit of code is supposed to do, but not why it doesn’t work as expected.
function addLinks()
{
for (var i=0, link; i<5; i++)
{
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function ()
{
alert(i);
};
document.body.appendChild(link);
}
}
window.onload = addLinks;
To be clear, this is a small function that will add five links to the page that read Link 0, Link 1, Link 2, etc. and, when clicked, will pop up an alert
box with that link’s number, such as 0, 1, 2, etc. I know appending to the DOM inside a loop is bad practice and that these links are not inside of a block-level entity. For now pretend that these things aren’t important. What is important is that clicking on any of these links will always alert
4 instead of the number belonging to that link.
Global scope is the enemy of predictability
As the loop iterates, the variable i
is being incremented and that number is applied to the individual links as they are made – so what’s happening here? JavaScript’s ultra-friendly, as-global-as-possible scope is stealthily making trouble. For example, if you were to break that loop when i
was set to 3, for example, all links would alert
3.
You see it yet? Exactly. The variable i
is set in the global sense of the page and each link is referring to the global instance of i
, not its own local scope. So if I were to run this function then type javascript:i='foo';
in my address bar each link would alert
foo. You’re right to think there has to be a way around this.
Bringing them together
So you have a function using a variable but the scope is out of whack? Let’s see if a closure can help! The trick will be to create a function that only knows what you tell it and make that function what gets called on the onclick
. If that doesn’t make sense, read it again and then look at the code. The syntax and execution of closures is fairly counter to most programming techniques so putting yourself in that mindset will take some adjustment. A bit of updated code should help.
function addLinks()
{
for (var i=0, link; i<5; i++)
{
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function (num)
{
return function ()
{
alert(num);
};
}(i);
document.body.appendChild(link);
}
}
window.onload = addLinks;
The onclick
is now bestowed with a closure and that closure is binding the i
‘s value into its own local scope so that you can change i
to be whatever you like and the closure will always remember what it was when you called it. The closure is invoked by the (i)
at the end of the function, making it a self-invoked function. When it is invoked the i
is passed in, assigned to the num
variable which makes it a local, contained variable. Then an anonymous function is returned that will be called when the onclick
is triggered. That anonymous function doesn’t have its own num
variable so it looks up the scope chain, sees one in the onclick
and uses it.
That last paragraph might need a few passes to fully understand. Don’t worry, closures are a complicated concept to learn for programmers not well versed in functional languages. In upcoming entries I’ll talk about stretching JavaScript in two different but powerful ways: lambda functions and exploring public and private variables. Stay tuned!
Recommend reading:
June 6th, 2009 § Comments Off on How JavaScript libraries save and waste your time § permalink
JavaScript libraries are the best thing to happen to JavaScript since it was shoehorned into Netscape, way back in 1995. They are also a nightmare for developers. How can this be? Certainly, with the breadth of libraries offered today surely there must be one, best choice. Like many things in life, it’s never as easy as picking the best or even the least horrible.
History
Let’s rewind a bit. JavaScript was invented by Brendan Eich, originally under the title of Mocha. This next bit always gets JavaScript aficionados’ (like myself) skirts ruffled but JavaScript is not a true programming language. It is a scripting language, weakly typed, dynamically interpreted and without a true OO structure. There’s no garbage collection, no typing and very few data structures. By comparison, C is downright drowning in features.
As if being a scripting language wasn’t enough, JavaScript is also implemented in different manners and levels by the many browsers, suffers from proprietary functions (XMLHttpRequest, anybody?) and can fall flat on its face if the DOM isn’t properly rendered. It’s a veritable mine field of hacks and work-arounds to get a decently-sized system working for the majority of the web.
Of course every language has its disadvantages and in face of AJAX, new JavaScript engines and the growing amount of mashups and services offered on the web, JavaScript continues to shine in its flexibility. The language hasn’t even released v2.0 and businesses like Flickr, Google, Yahoo leverage entire products on JavaScript. There must be something to the language, so what am I getting on about?
Lifespan
Like it or not most JavaScript libraries are immature. Sure, there have been great guys like Dean Edwards, who have been cobbling together scripts and hacks into a convenient wrapper, calling them a library. I’m not knocking that work at all. It’s paved a long road to where the community is today and the work is not only well done, but still relevant.
What I am saying is that full libraries with helper functions, effects, AJAX and the other myriad of tools which can be provide have only been on the scene for a short time. They have experienced a massive burst of growth, thanks to active communities and their use on high profile websites. They have explored new and innovated means of developing UI and data interaction and have even begun standardized competition between each other.
Still, who knows where these libraries will be in two years, five years or ten years. I can hear the collective scoffs of developers right now. Just upgrade the library, you say. Keep with the times, grandpa! It’s not that easy, buckaroos. When you’re developing for an enterprise you need to think about things like a life cycle measured in years, vendor support and development. I don’t want to be responsible for digging through a few thousand lines of JS code in a few years just because the new IE now requires me to hack up my library so that Windows folk can validate my form on the client side.
Truth be told, the only library with plausible hope of long-term life is the Yahoo! User Interface library. It’s well designed, relatively fast, has had some great minds working on it and Yahoo! isn’t likely to disappear any time soon. Great though the rest may be, there is no proof that they’ll be around next week, only the hope.
Syntax
This one is so obvious that many people overlook it. Learning a new JavaScript library requires learning new syntax. This isn’t a bad thing because the point of many of these libraries is to do more work with less code. Being able to select elements based on CSS selectors by typing $$('.myclass');
is a veritable dream come true. Still, each library has its own flavor and none of them are fully compatible.
For 90% of the users, the syntax is a time-saver and becomes second nature. Those last 10% are folks who just want to get something done in JS and can’t be bothered to deal with new syntax or, heaven forbid, are transitioning from one library to the other. Using some clever code an automated conversion script could be generated to make the move from one library to another but this is more work in yet another language.
It’s just one of those Catch 22 situations where you’re damned if you do and damned if you don’t. Thankfully, I fall into the 90% of folks who love their new syntax and wouldn’t trade it for all the money in a hobo’s pocket.
Performance
This is a tough topic to cover. Until slickspeed there was no universal, honest test of libraries. It was mostly developers talking about how they made their iterators 500% faster or have new CSS3 selectors. I’m sure more testing suites will be developed but for now it comes down to developers deciding which features are best supported in a library and hoping that either the speed is quick enough or that it will improve in the near future.
Capabilities
Support
I eluded to this earlier but it deserves more attention. Support from your third-party is crucial to anybody who is serious about coding. Trust me, I love hacking code into the wee hours of the night, but only when it’s my code. I do not consider it a good time to be debugging someone’s plugin or extension because they didn’t properly test and I’ve stumbled upon an edge case.
A good vendor will have dedicated support staff, an active community – perhaps with a sponsored forum – and, if you’re lucky, a few developers dedicated to the product. There will be the opportunity to pick up the phone and get support 24/7, maybe even have a local technician come out and do on site support. Sure, these services aren’t free, but in a crisis it’s reassuring to know they’re available.
Honestly, I don’t expect that kind of support from any JavaScript library. Yet. Google is huge and can support their own code as much as they please. Joe website guy has enough time on his hands to support what he writes and isn’t under enterprise-level support needs. It’s that middle ground where you have a dozen projects running simultaneously and the project manager doesn’t understand why you allocated 10 hours to the menu system but suddenly you’re telling her it will be 20 because you’re running into an obscure bug in IE 5.5 for the Mac.
With the the JavaScript performance race between Firefox and Safari (IE8, you still don’t make the cut) JavaScript is prime to become a crucial aspect of companies with internet-based products. I know that sounds like something out of 1995 but, really, there are many popular applications which either do not use JavaScript or have it as an ancillary feature-add. As the canvas tag gains more support and JavaScript becomes faster entire apps could move their features online. None of the half-functional things like Word online but real applications: Page layout, bitmap editing, 3d modeling, you name it.
None of that is going to happen without support from vendors. Do you really think Autodesk, makers of heavy applications, really wants to invest the time and long-term money into writing a 3ds Max JavaScript library? Not likely. They’ll want to take money which is pennies to them, say $15,000, and license a library that does what they need. They’ll do this because when things break they can just pick up the phone and have it fixed. It’s cheaper to pay $250 in a day’s worth of support than keeping a $75,000 salaried employee around all the time.