JavaScript Techniques

ESPN • Scott Sauyet • July 13-14, 2010



JavaScript Techniques
===================

### Scott Sauyet ###

An overview of intermediate and advanced techniques in JavaScript.



What Is JavaScript?
===================

* The scripting language of the Web.
* Created by Brendan Eich of Netscape.
* Copied (warts and all) by Microsoft for Internet Explorer, by Opera, and by
  others.
* Standardized by European Computer Manufacturer's Association, and officially
  known as ECMAScript.
* Now on the 5th edition of the ECMA-262 standard, since December 2009.  Most 
  browsers are still on the 3rd edition.



Other Environments
==================

JavaScript can run in other environments than the browser.

* [Rhino] for Java applications.
* [Apple Dashboard Widgets], [Microsoft Gadgets].
* Plug-in environments for many tools, such as [Yahoo! Messenger].
* Flash/Flex.  Actionscript is just an ECMAScript dialect.
* [Server-side environements], most recently [Node].



General Javascript References
=============================

The set of references for JavaScript is spotty at best.

* Books: there are only two general-purpose JavaScript books worth reading.
* Online References:  Mozilla's reference pages are thorough and useful, but
  difficult to navigate and very slow to load.  Microsoft's are hard to find
  and often incomplete or incorrect.  These are still important sources.
* Online Tutorials: Mostly a waste of time.
* Library References:  There are some pretty well documented libraries.  And 
  many that aren't.



JavaScript Books
================

Only two great books out:

* _[Javascript: The Definitive Guide]_, by David Flanagan.  This is the best 
  accessible description of the language available.
* _[JavaScript: The Good Parts]_ by Douglas Crockford.  This short book 
  discusses what JavaScript got right, and what should be skipped.  It's 
  opinionated and thoughtful, and a quick read.

Not out yet:

* _[Secrets of the JavaScript Ninjas]_, by John Resig,
  original author of [jQuery].  This book has some interesting advanced 
  techniques in it, but not all of them are great ideas.



Online References
=================

* The [Mozilla Developer Center] has lots of good information, and much of it
  is relevant to most browsers.  It is slow to load, and sometimes difficult to
  navigate, but the information is quite useful, especially concerning the APIs.
* Microsoft's [JScript documentation] is less complete, less useful, and equally 
  hard to navigate, but is the only source for certain information related to 
  Internet Explorer.
* [Wikipedia](http://en.wikipedia.org/wiki/JavaScript) has mostly correct
  and sometimes complete information on JavaScript.
* Peter-Paul Koch maintains the best list of browser compatibility information
  at [Quirksmode].


Online Tutorials
================

* Recommended
    - [Brown University CS Department Tutorial] is old and very basic, but 
      correct and good for beginners.
    - [Essential JavaScript] by Patrick Hunlock is a pretty good overview of the
      language.
* Not recommended
    - [About.com: Javascript] is out of date and filled with misinformation.
    - [w3Schools.com] seems to be about ten years out of date.
    - Almost everything else.



Other Resources
===============

* [Crockford's Videos] on Yahoo! Video teach many levels of JavaScript.  He is
  not only knowledgeable, but also a very good instructor.
* The [ECMAScript Specification] (or [Version 3] [ECMAScript Specification 3])
  is not for the faint-hearted, but it does get you all the gory detail you'll 
  ever want.
* Mailing Lists and News Groups: A mixed bag, but the best bet to learn more
  advanced techniques.  [comp.lang.javascript] is the best-known of them.  It is
  populated with many pedantic, obnoxious personalities.  However these are
  often the most knowledgeable people in the forum.



What Does JavaScript Have to Do With Java?
==========================================

* **Nothing!**  The name was just a marketing ploy between Sun and Netscape.
* JavaScript can be used to script Java applets, but it can equally well script
  other plug-ins, such as Flash or PDF.
* It does share superficial syntactic similarities with Java.  This is 
  legitimate in either language:

>     for (i = 0; i < myArray.length; i++) {
>         if (i % 3 == 0) {
>             doSomething(myArray[i]);
>         } else {
>             myArray[i] = i * myArray[i];
>         }
>     } // end loop



Types in JavaScript
===================

## There are only six data types in JavaScript: ##

1. **Number**: A 64-bit floating point number
2. **String**: A list of characters
3. **Boolean**: `true`, `false`
4. **Null**: Exactly what you expect, only one value: `null`
5. **Undefined**: Mostly what you expect.  Only one value, the global property
   `undefined`.  (Note that this is **not** a keyword)
6. **Object**: Everything else.  Discussed next

Note that a variable is not specifically bound to a type.



JavaScript Objects
==================

* No classes.  All objects are of type Object.
* Objects are simple Hash Maps, dictionaries.
* Property names can be any String.
* Property values can be any type, including other objects.
* Objects are always passed by reference, never copied.



Two Flavors of Property Access
==============================

>     myObject.prop1 = "red";
>     myObject["prop2"] = "green";

* These two are entirely equivalent.
* The second is more wordy, but more flexible, as it lets us use any String
  whatsoever as a property value.



Traditional Creation
====================

Objects can be created and modified like in Java:

>     var house = new Object();
>     house.style = "ranch";
>     house.color = "red";
>     house.available = true;
>     house.price = 249900;
>     var realtor = new Object();
>     realtor.name = "John Q. Public";
>     realtor.phone = "800-867-5309";
>     var contacts = {};
>     contacts.owner = "Jane Doe";
>     contacts.realtor = realtor;
>     house.contacts = contacts;



Object Literals
===============

Object literals are an easy way to create one-off data structures.  This is 
entirely equivalent to the previous code:

>     var house = {
>         style: "ranch",
>         color: "red",
>         available: true,
>         price: 249900,
>         contacts: {
>             owner: "Jane Doe",
>             realtor: {
>                 name: "John Q. Public",
>                 phone: "800-867-5309"
>             }
>         }
>     };



Array Literals
==============

Array literals have a similar syntax:

>     var smallInts = [1, 2, 3, 4, 5];
>     var primaries = ["red", "blue", "yellow"];

You could of course use the more verbose syntax:

>     var primaries = new Array();
>     primaries[0] = "red";
>     primaries[primaries.length] = "blue";
>     primaries.push("yellow");

And you can nest object and array literals (as deeply as you like):

>     var points = [{x : 3, y : 4}, {x: 5, y : 2}];



Arrays
======

Arrays are objects whose properties are named by sequential small integers.
They have a `length` property, but its behavior is a little surprising.

>     var x = new Array();
>     x[0] = 'a';
>     x[x.length] = 'b';
>     x.push('c');
>     
>     alert(x.length); // 3
>     
>     x[5] = 'f';
>     
>     alert(x.length); // 6
>     alert(x); // ["a", "b", "c", undefined, undefined, "f"]



Using Objects as Namespaces
===========================

Too much JavaScript code ends up in the global namespace.  This is especially
problematic when you start using multiple different sources of JavaScript,
including third-party libraries.  One technique to avoid this is to use an 
object as a namespace for your data and functions:

>     var myNamespace = myNamespace || {};
>     myNamespace.count = 0;
>     myNamespace.increment = function() {
>         this.count++;
>     }
>      
>     myNamespace.increment();
>     alert(myNamespace.count); // 1
>     alert(count) // error



Prototype Chain
===============

* Every object inherits properties from a prototype object, which inherits
  properties from a prototype of its own, all the way up to the root object.
* Just like with Java, there are functions like `toString()` defined on the
  root.
* This is a very different notion of inheritance than Java.  Any object can be
  enhanced with additional properties at any time.  This includes prototypes, 
  which means that you can have simple run-time enhancement to your "classes".
* When setting a property on an object, the prototype is ignored.  But you can
  do this:

>     myConstructor.prototype.prop1 = value;




Functions
=========

* First of all, Functions are first-class Objects.
* They can be properties of other objects

>      function sellHouse(house, buyer) {
>          // ...
>      }
>      realtor["make-commission"] = sellHouse; 

* They can be passed around like any other object

>      validateCredit(sellHouse, rejectSale);



Function Syntax
===============

* Functions don't have names.  This syntax:

>     function myFunc(params) {
>         // ...
>     }

is just shorthand for this:

>     var myFunc = function(params) {
>         // ...
>     }

* I prefer the latter syntax to keep it clear that the function is just another
  object.  It just happens to be assigned as the value of the variable myFunc.



Functions as Constructors
=========================

You can simulate some Object-Oriented techniques by using functions as
Constructors:

>     var Rectangle = function(w, h) {
>         this.width = w; this.height = h;
>     };
>     Rectangle.prototype.area = function() {
>         return this.width * this.height;
>     };
>     var rect = new Rectangle(7, 6);
>     alert(rect.area()); // 42

The `new` is mandatory.  The capital letter for the constructor name is customary.



Constructor Functions Are Not Classes
=====================================

>     var rect1 = new Rectangle(7, 6);
>     var rect2 = new Rectangle(3.14159, 2.71828);
>     rect1.color = "red";
>     rect2.perimeter = function() {
>         return 2 * (this.width + this.height);
>     }
>     
>     alert(rect2.color) // undefined
>     alert(rect1.perimeter()) // error

`rect1` and `rect2` have not just different values for their common properties,
but also distinct properties.



Prototypes are Live
===================

>     Rectangle.prototype.diagonal = function() {
>         return Math.sqrt(this.width * this.height);
>     };
>     
>     alert(rect1.diagonal()); // 6.4807406040786
>     alert(rect2.diagonal()); // 2.9222801483088507

Note that some implementations also allow you to access the prototype of an 
object directly:

>     rect1.__proto__.isSquare = function() {
>         return this.height === this.width;
>     };



Functions are never just Methods
================================

Functions can be called in the global context:

>     myFunc();

They can also be called in the context of an object:

>     rect1.area();

But they can also be called in an arbitrary context:

>     var myObject = {width: 10, height: 12};
>     Rectangle.prototype.area.call(myObject);



Call and Apply
==============

Functions are objects, and hence can have properties.  All functions inherit
the methods `call()` and `apply()`.  The first parameter to each is the context
in which the function will run.

For `call()` the subsequent parameters become the parameters passed to the
function.  For `apply()` there is a second parameter which is an array 
containing all the parameters to be passed along.

>     var expand = function(dw, dh) {
>          this.width += dw; this.height += dh;
>     }
>     expand.call(rect1, 2, 3);
>     expand.apply(rect2, [-0.14159, 0.28172]);



Enhancing Built-in Objects
==========================

Any object can be enhanced, including prototypes for built-in objects.

>     String.prototype.trim = function() {
>         return this.replace(/^\s+|\s+$/g, '');
>     }

This is controversial.  There are fairly good reasons for not doing this, at
least for HTML elements.  But it can be very convenient.  One important point,
though, is not to enhace the Object.prototype.  This can cause serious problems
when you try to interact with other JavaScript tools.



Dynamically Creating Functions
==============================

Functions can be created as needed, the way other objects are.  You can return
anonymous functions as the result of calls.

>     function createClickHandler(nbr) {
>       return function() {
>           alert("You clicked dead link " + (1 + nbr));
>       }
>     }
>     var links = document.getElementsByTagName("A"), count = 0;
>     for (var i = 0; i < links.length; i++) { 
>       var link = links[i];
>       if (link.getAttribute("href") == "#") {
>         link.onclick = createClickHandler(count++);
>       }
>     }



Scope of Variables
==================

>     function createClickHandler(nbr) {
>       return function() {
>         alert("You clicked dead link " + (1 + nbr));
>       }
>     }
>     var links = document.getElementsByTagName("A"), count = 0;
>     for (var i = 0; i < links.length; i++) { 
>       var link = links[i];
>       if (link.getAttribute("href") == "#") {
>         link.onclick = createClickHandler(count++);
>       }
>     }

All the variables available in the global scope, including "count", "links", the 
function "createClickHandler", and even "i" and "link".



Function Scope
==============

* JavaScript does not have block scoping.
* Even loop iteration variables are available throughout the rest of that 
  function.
* All variables are scoped to the function in which they're defined or to the
  global scope.
* Without the `var` keyword, they are global.



Reducing the Scope by Wrapping a Function
=========================================

>     function addClickHandlers() {
>       function createClickHandler(nbr) {
>         return function() {
>           alert("You clicked dead link " + (1 + nbr));
>         }
>       }
>       var links = document.getElementsByTagName("A"), count = 0;
>       for (var i = 0; i < links.length; i++) { 
>         var link = links[i];
>         if (link.getAttribute("href") == "#") {
>           link.onclick = createClickHandler(count++);
>         }
>       }
>     }
>     addClickHandlers();



Removing all Global Namespace Properties
========================================

The previous technique reduced our global variables to only one: 
`addClickHandlers`.  But this is never used again.  Instead we can make it an 
anonymous function, and execute that function immediately:

>     (function() {
>         // Anything defined here is
>         // invisible to the global scope.
>     })();

This is sometimes called "immediate invocation".  The technique was pioneered
by Richard Cornford, and a few people have recently taken to calling it
"Cornford's Construct" or "Cornifying".  Cornford himself is not amused by this.



Quick Question
==============

Is there something surprising about this:

>     function createClickHandler(nbr) {
>         return function() {
>             alert("You clicked dead link " + (1 + nbr));
>         }
>     }
>     var myFunc = createClickHandler(19);



Closures
========

There is something that might be surprising about this:

>     function createClickHandler(nbr) {
>         return function() {
>             alert("You clicked dead link " + (1 + nbr));
>         }
>     }
>     var myFunc = createClickHandler(19);

When the `createClickHandler` function returns a new function, it seems as 
though `nbr` should go out of scope.  Instead JavaScript creates a **closure**
of all variables in scope.  `myFunc` has access to (and can change) those
values when it's called.



Notes on Closures
=================

* Closures can be used to simulate private object properties in Javascript.
  Douglas Crockford [published] [crockford private] this in 2001.
* There was a period where creating closures was frowned on for performance
  reasons.  But it's gotten to the point where looking up items from a closure
  is faster than looking it up from a global variable.
* Closures are not difficult.  The difficulty is in adapting the mindset from 
  other languages.
* There are gotchas, especially having to do with loop variables.
* The first few links on a [Google Search](http://www.google.com/search?q=javascript+closures)
  for "javascript closures" are actually pretty good references.  Richard
  Cornford's FAQ entry is the most complete, but the least accessible.


Closure Example
===============

An example from [Webreference] [webref closure] shows how we can extend the 
`document.createElement` function to accept additional parameters such as id and 
classname:

>     document.createElement = (function (fn) {
>         return function (type, id, className) {
>             var elem = fn.call(document, type);
>             if (id) elem.id = id;
>             if (className) elem.className = className;
>             return elem;
>         };
>     })(document.createElement);



Closure Loop Gotcha
===================

>     var rows = myTable.getElementsByTagName("TR");
>     for (var i = 0; i < rows.length; i++) {
>         $(rows[i]).click(function() {alert("Clicked row " + (i + 1)};}); 
>     }

This looks as though it will alert the number of the current row on a click.

In fact, though, it alerts the final value of i (one more than the number of
rows.)



One Fix for Closure Loop Gotcha
===============================

A new function creates an additional closure, capturing the loop variable:

>     var myTable = document.getElementsByTagName("TABLE")[0];
>     var rows = myTable.getElementsByTagName("TR");
>     for (var i = 0; i < rows.length; i++) {
>         $(rows[i]).click(createClickHandler(i + 1));
>     }
>     function createClickHandler(row) {
>         return function() {alert("Clicked row " + row);}
>     }


Another Fix for Closure Loop Gotcha
===================================

This does much the same thing.  It is in some sense more elegant as there is no
need to name the anonymous function in the previous version.  But it is more
complex syntactically:

>     var myTable = document.getElementsByTagName("TABLE")[0];
>     var rows = myTable.getElementsByTagName("TR");
>     for (var i = 0; i < rows.length; i++) {
>         $(rows[i]).click((function(row){return function() {
>             alert("Clicked row " + row);}
>         })(i + 1));
>     }



An Apology for the Next Slide
=============================

There is a hard-and-fast rule that all discussions of functional languages
have to touch on one of the two **F**'s: `factorial` or `fibonacci`.

We all know that I'm a stickler for rules, right?

Sorry about that.



Using a Closure to Cache Results
================================

>     function memoize(f) {
>         var cache = {};
>         return function (n) {
>             return (n in cache)? cache[n] : cache[n] = f(n);
>         };
>     }

It can then be used like this:

>     function fibonacci (x) {
>         if(x < 2) return 1; 
>         return fibonacci(x-1) + fibonacci(x-2);
>     }
>     fibonacci  = memoize(fibonacci)
>     alert(fibonacci(100)); // 573147844013817200000



Function Arguments
==================

When a function is invoked, it has access to another variable, `arguments`.

This can be used like varargs in Java:

>     var sum = function() {
>         var total = 0;
>         for (var i = 0; i < arguments.length; i++) {
>             total += arguments[i];
>         }
>         return total;
>     }
>     var degreeDays = sum(98, 94, 102, 99, 89, 93, 101); // 676



More About Arguments
====================

`arguments` is array-like, but it is not an array, and does not have the array 
methods assigned to it.

This can be overcome by applying the array methods directly:

>     var first = Array.prototype.shift.apply(arguments);

`first` now contains the original first element from the arguments array, and
`arguments` has had its first element removed.  All the Array methods can be
called in this manner.



Arguments.callee
================

`arguments` also has a property, `callee` which points back to the function
being called.  This is very useful for anonymous recursion:

>     setTimeout(function() {
>         if (checkCompleted() {
>             // do something
>         } else {
>             setTimeout(arguments.callee, 100);
>         }
>     }, 100);

Note that the function passed to `setTimeout` is never named, but is still
called recursively.  This is very powerful, but gets tricky to debug.



Named Function Expressions
==========================

An alternate technique for anonymous recursion is to use a named function 
expression.  This helps in the debugger.

>     var foo = function bar() {
>         // here "bar" is available for recursive calls
>     }
>     // here "bar" is undefined... or should be by the spec.

Internet Explorer gets this wrong, in some fairly bizarre ways, through IE8, and
maybe beyond.  In IE, `bar` is still defined in the outside scope, and it points
to a **different copy** of the same function that `foo` points to.

This wastes memory and can occasionally lead to bugs, but doesn't invalidate
its usefulness in some circumstances.



Options Object
==============

There is no overloading in JavaScript.  There is only one function with a given
name in a particular scope.  Using the arguments object allows us to examine
the arguments passed and analyze their type to see what information is really
needed.  But the named parameters to a function can get hairy when some of them
are optional.  An alternate technique is to pass in a single object with all the
parameters listed by name:

>     var result = myFunc({
>         size: 10, 
>         color: "red",
>         invert: true,
>         owners: ["Alice", "Bob", "Christine"]
>     });



Libraries
=========

There are numerous JavaScript libraries available to help with specific tasks.
A small number of them are of reasonably good quality.  Most are awful.  There 
are also general-purpose libraries meant to help with large parts of building 
your JavaScript application.  The best-known of these are:

* Prototype/Script.aculo.us
* Dojo
* YUI (Yahoo User Interface)
* Ext
* MooTools
* jQuery



Prototype/Script.aculo.us
=========================

Prototype is the great-grandadddy of modern JS Libraries.  It was created as 
part of Rails, and is much inspired by Ruby.

>     $('comments').addClassName('active').show()

Heavy on modifying the prototypes of built-in objects.

Script.aculo.us is a add-on that adds animations, effects, drag-and-drop, and 
some additional functionality.  This keeps the Prototype core relatively small.

Prototype seems to be falling out of favor.  It's not being updated as much and 
mindshare seems to be moving toward jQuery.



Dojo Toolkit
============

Dojo has also been around for years.  It never really makes clear what its
defining features are supposed to be.

>     dojo.style("basicFadeNode", "opacity", "0");
>     dojo.fadeIn({node: "basicFadeNode"}).play();

This was originally an IBM-led consortium attempting to collect general 
best-practices, and some of that shows in it's fairly jumbled API.

If this hadn't already gotten a foothold in a number of large corporations, it
could officially be called dead.  But there are always people working on it.



YUI
===

Designed for building rich interactive applications on the web.  It focuses more
than the previous two on widgets and highly visible DOM changes.

>     YUI().use('anim-base', function(Y) {
>         var anim = new Y.Anim({
>             node: '#demo',
>             to: { opacity: 0 }
>         });
>         anim.run();
>     });

There are many complaints about YUI being bloated and very slow to download but
it is generally responsive and useful once downloaded.



Ext
===

Ext is a widget library.  Any other features are secondary.  It is by far the
snazziest widget library available, and probably the best documented as well.
It depends on a pluggable core, and can be used on top of its own core or 
Prototype, jQuery, or YUI.

>     var win = new Ext.Window({
>         id : 'myWindow',
>         title : 'My first Ext JS Window',
>         width : 300, height : 150, layout : 'fit',
>         autoLoad : { 
>             url : 'sayHi.html',
>             scripts : true
>         }
>     });
>     win.show();



MooTools
========

MooTools is all about object-orientation.  It is considered by its proponents
as an abstraction layer between the browser and your code.  It tries to smooth
over the differences between the browsers and enhance them by adding to the 
core objects and adding utility objects.

>     window.addEvent('domready', function(){
>         new SimpleImageSlideShowDemo({
>             imgUrls: [
>                 "slide1.jpg",
>                 "slide2.jpeg",
>                 "slide3.jpeg",
>             ],
>             container: $('imgContainer')
>         });
>     }); 



JQuery
======

"Find something; do something."  The jQuery mantra is simple.  jQuery is 
focused on easily selecting the DOM items you want and performing simple 
operations on them.  It's keeps a fairly small core but has a powerful and 
easy-to-use plug-in mechanism.

>     $("tr:nth-child(odd)").addClass("odd");

jQuery is perhaps the easiest library to learn.  It also has a strong evangelism
team.  These have helped make it the recent king of the libraries.  This is fine 
with me as it's my favorite among them.

We'll examine more deeply how to use it, but first a little about its flaws.



JQuery Issues
=============

* jQuery makes it perhaps **too** easy to simply find some elements and add
  handlers to them.  This ignores the benefits that could be gained from
  event delegation.
* jQuery's general API is relatively easy to remember, but the main function, 
  `jQuery` (aka `$`), is terribly overloaded.  It can be used to
    - create a wrapped collection of elements from a selector, a DOM element, an
      array of DOM elements, another wrapped collection, or the clear blue sky
    - build a new wrapped HTML element from a string, or build one and set 
      properties and run functions on it.
    - run a callback function once the DOM is ready
* Its attribute handling is a convoluted mess that might or might not do what
  you need.



Using JQuery
============

Example:  To zebra-stripe all tables on the page using CSS class "odd":

>     $("tr:nth-child(odd)").addClass("odd");

To do this only on tables that have the class "zebra"

>     $("table.zebra tr:nth-child(odd)").addClass("odd");

Example:  To add a hover class to rows when the mouse is over them:

>     $("tr").hover(function() {
>         $(this).addClass("hover");
>     , function() {
>         $(this).removeClass("hover");
>     });



JQuery Notes
============

* `$` is just an alias to the `jQuery` main function.  These are the only 
  global variables exposed by jQuery.
* At the heart of jQuery is its CSS selector engine.  It's quite easy to
  find elements you care about, using CSS and some extensions to CSS.
* The jQuery object that's created is a wrapper around a number of DOM elements
  and most methods work on them as a group.  You don't need to check the size
  of the collection or iterate over it, just call methods on it.  But you have
  array-like access to the elements as needed.
* Most jQuery code should run only after the DOM content is loaded:

>     $(document).ready(function() {
>         // your code here
>     }


Example: This Presentation
==========================

* [S5] is Eric Meyer's Simple Standards-based Slide Show System.  It uses a
  format compatible with Opera Show to make Powerpoint-like slide shows out of
  HTML documents.
* I wanted a document structure simpler to read than HTML, though.
* [Markdown] is an easy-to-read plain text format that can be converted in a 
  straightforward manner to HTML.
* [Showdown] is a port of the Perl Markdown implementation into JavaScript.
* Combining these with some custom code using jQuery allows me to still have an
  easy-to-type, easy-to-read presentation that is quite clear when JavaScript
  is off.

(view source here)


Creating S5 Control Structures
==============================

>     $("body").prepend('<div class="layout"><div id="controls"></div>'
>            + '<div id="currentSlide"></div><div id="header"></div>'
>            + '<div id="footer"></div></div>');
>     $("#footer").append($("h1, h2"));
>     var $presentation = $('<div class="presentation">')
>                         .appendTo("body");



Calling Showdown on Content
===========================

>     var origText = $("#contents").remove()
>                                  .html()
>                                  .replace(/&gt;/g, '>')
>                                  .replace(/&lt;/g, '<')
>                                  .replace(/&amp;/g, '&');
> 	var converter = new Attacklab.showdown.converter();
> 	var text = converter.makeHtml(origText);




Tranforming Markdown Output to S5
=================================

>     var slides = [], started = false,
>         index = text.indexOf('<h1>'), index2;
>     while (index > -1) {
>         slides.push(text.substring(0, index));
>         if (started) slides.push('</div>');
>         text = text.substring(index + 4);
>         index2 = text.indexOf('</h1>');
>         if (index2 > -1) {
>             slides.push('<div class="slide"><h1>' + 
>                 text.substring(0, index2) + '</h1>');
>             text = text.substring(index2 + 5);
>         }
>         index = text.indexOf('<h1>');
>         started = true;
>     }
>     slides.push(text + '</div>');
>     $presentation.append(slides.join(''));


Running S5 Script
=================

>     var script = document.createElement('script');
>     script.type = 'text/javascript';
>     script.src = 'ui/default/slides.js';
>     $("body").append(script);


Summary
=======

* JavaScript has rightly been [called] [crockford misunderstood] "The World's 
  Most Misunderstood Programming Language."
* It's been misunderstood partly because so much of what's available is not
  written in a professional manner.
* It can be written well, perform well, and scale to quite large applications.
* Although it looks like C, it acts much more like LISP.
* In many cases, it's the only game in town, so learning to do it right really
  is useful.



  [About.com: Javascript]: http://javascript.about.com/
  [Apple Dashboard Widgets]: http://www.apple.com/downloads/dashboard/
  [Brown University CS Department Tutorial]: http://www.cs.brown.edu/courses/bridge/1998/res/javascript/javascript-tutorial.html
  [comp.lang.javascript]: http://groups.google.com/group/comp.lang.javascript
  [crockford misunderstood]: http://www.crockford.com/javascript/javascript.html
  [crockford private]: http://www.crockford.com/javascript/private.html
  [Crockford's Videos]: http://video.yahoo.com/watch/111587/1027854
  [ECMAScript Specification]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
  [ECMAScript Specification 3]: http://www.mozilla.org/js/language/E262-3.pdf
  [Essential JavaScript]: http://www.hunlock.com/blogs/Essential_Javascript_--_A_Javascript_Tutorial
  [Javascript: The Definitive Guide]: http://oreilly.com/catalog/9780596000486
  [JavaScript: The Good Parts]: http://oreilly.com/catalog/9780596517748/
  [jQuery]: http://jquery.com/
  [JScript documentation]: http://msdn.microsoft.com/en-us/library/hbxc2t98.aspx
  [Markdown]: http://daringfireball.net/projects/markdown/
  [Microsoft Gadgets]: http://en.wikipedia.org/wiki/Microsoft_Gadgets
  [Mozilla Developer Center]: https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide
  [Node]: http://nodejs.org/
  [Rhino]: http://www.mozilla.org/rhino/
  [Quirksmode]: http://www.quirksmode.org/
  [S5]: http://meyerweb.com/eric/tools/s5/
  [Secrets of the JavaScript Ninjas]: http://jsninja.com/
  [Server-side environements]: http://en.wikipedia.org/wiki/Comparison_of_Server-side_JavaScript_solutions
  [Showdown]: http://attacklab.net/showdown/
  [w3Schools.com]: http://www.w3schools.com/js/default.asp
  [webref closure]: http://www.webreference.com/programming/javascript/rg36/
  [Yahoo! Messenger]: http://developer.yahoo.net/blog/archives/2010/06/ymessenger_api.html