JavaScript, even more so than VB, has to be the Rodney Dangerfield of programming languages. I'm going to blow whatever credibility I might have by saying "I actually like programming in JavaScript." I'm actually building a lot of the screens in StoryTeller with JavaScript running in a WebBrowser control because I think I can do dynamic layout much faster with JavaScript than a WinForms screen. Besides, the point of a "side" project is to do stuff you don't get to do at your day job.
Check out this link from AdamLogic. Granted, I don't see a bunch of people running out to write applications in JavaScript alone, but I think Metaprogramming is going to become more common in the near future. I'm intrigued by all the ways people are creating little lexical languages to make the code get closer to the actual problem domain. Little ol' JavaScript is actually decent for building little embedded languages and using Metaprogramming.
As a thought exercise last year, I played around with using RoR style declarative metaprogramming with JavaScript classes to see if I could build DHTML controls and widgets faster. Take the example of a JavaScript control that has to create and control an internal hierarchy of DOM elements. Here was my attempt to pull some of the grunt work of DOM manipulation up into a common superclass:
function act_as_compound(target){
target.appendNamedChild = function(name, tag, props){
var child = document.createElement(tag);
this.appendChild(child);
// EDIT: removed the eval() call
this[name] = child;
if (props != null){
Object.extend(child, props);
}
return child;
}
target.appendSpan = function(name, props){
return this.appendNamedChild(name, 'SPAN', props);
}
target.appendDiv = function(name, props){
return this.appendNamedChild(name, 'DIV', props);
}
target.appendButton = function(name, props){
var btn = this.appendNamedChild(name, 'button', props);
return btn;
}
return target;
}
As an example, here's *part* of a Pager class I'm using inside StoryTeller. The Pager control is a DIV element with 4 child buttons and a SPAN element to show the current page. The usage of "acts_as_compound" inside Pager looks like this:
function Pager(pager, controller){
if (!pager){
pager = document.createElement('div');
}
// Metaprogramming constructs -- add in the methods to support the
// compound element
act_as_compound(pager);
controlled_by(pager, controller);
var pageFunction = function(){
controller.goToPage(this.pageNumber);
}
// Use the methods on act_as_compound to add child elements to the parent div
pager.appendButton('firstButton', {innerHTML: '|<', pageNumber: 1});
pager.appendButton('previousButton', {innerHTML: '<<'});
pager.appendSpan('pageSpan');
pager.appendButton('nextButton', {innerHTML: '>>'});
pager.appendButton('lastButton', {innerHTML: '>|'});
pager.buttons = [pager.firstButton, pager.previousButton, pager.nextButton, pager.lastButton];
pager.buttons.each( function(button){
button.controller = controller;
button.onclick = function(){
this.controller.goToPage(this.pageNumber);
}
});
return pager;
}
In particular, look at a single call to "appendButton." That method does a couple different things. It creates a new button element, sets any of the properties ({innerHTML: '|<', pageNumber: 1} is effectively an anonymous object ala C# 3 defined in JSON), then use the eval() method to set a new member on the Pager object to the new button like this: this.firstButton = btn; Other methods in the Pager class contain code like "this.firstButton.enabled = true."
If you're interested, this JavaScript control is in the StoryTeller SVN repository in the folder: http://storyteller.tigris.org/svn/storyteller/trunk/src/StoryTeller.JavaScript/GreenJello.js. All of the JavaScript in StoryTeller leverages the Prototype library.
And yes, this is definitely a case of Safety (C# 2) versus Power (JavaScript or any other dynamic typed language + Obj C & C# 3 to some degree).
P.S. If you puked as soon as you saw the word "JavaScript," make sure to clean up;)