Learning from the jQuery source

Thursday, July 22nd 2010

A while back, I watched a video by Paul Irish titled “10 Things I Learned from the jQuery Source”.

One thing I particularly liked, is the way jQuery has undefined passed as a parameter to its main function.

In JavaScript all variables are declared globally. This makes it really easy for different scripts on the page to “clobber” (to use a Crockford phrase) each other, for example:

// script1.js
var name = "Pete";
// script2.js
var name = "Sarah";
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Example</title>
    </head>
    <body>
	<script src="script1.js"></script>
	<script src="script2.js"></script>
	<script>
	alert(name);  // "Sarah"
	</script>
    </body>
</html>

Taking this idea a bit further suppose in script1 we changed the value of a built in…

undefined = "Jam";

This is particularly scary as I see lots of code that checks against undefined:

var something;
if (something === undefined) {
	alert(name); // err... no alert shown
}

jQuery’s way to get around this is to take an extra parameter to its main function that is never set. Essentially getting its own “copy” of undefined to test against:

(function(window, undefined) {
	if (foo === undefined) {
		// works as expected
	}
}(this))

Clever stuff.


I am a huge fan of the Sinatra web framework for Ruby and have been desperate for some of its goodness in .NET.

For those that don’t know, Sinatra is great for building tiny web apps and services.

After playing with System.Web.Routing I figured it would be pretty simple to build a Sinatra clone in .NET.

Here is a simple Sinatra app:

require 'rubygems'
require 'sinatra/base'

class App < Sinatra::Base
  get '/' do
    'Hello'
  end
end

and its equivalent Jeff app:

using Jeff;

public class App : Handler
{
    public override void Routes()
    {
        Get("/hello", () =>
        {
            return "Hello";
        });
    }
}

The code is up on GitHub complete with a demo app.

Here is a more complicated example showing what Jeff can do:

using Jeff;

public class App : Handler
{
    public override void Routes()
    {
        Get("/hello", () => "Hello!");
        
        Post("/hello", () =>
        {
            return "posted: " + Params["example"];
        });

        Put("/hello", () => "Hello! PUT");

        Delete("/hello", () => "Hello! DELETE");

        Get("/hello/{name}", () =>
        {
            return string.Format("Hello {0}", Params["name"]);
        });

        Get("/resource.{format}", () =>
        {
            switch (Params["format"])
            {
                case "txt":
                    ContentType = Text;
                    return "A text file";
                case "html":
                    ContentType = Html;
                    return "<b>A</b> html <i>file</i>";
                case "json":
                    ContentType = Json;
                    return "{ \"name\" : \"value\" }";
                case "xml":
                    ContentType = "application/xml";
                    return "<xml><name>Xml</name></xml>";
            }

            return "Don't know what to do with this"; 
        });

        Get("/agent", () =>
        {
            var a = HttpContext.Request.Headers["User-Agent"];
            return string.Format("You're using: {0}", a);
        });

        Get("/callmethod", CallMethod);
    }

    private string CallMethod()
    {
        return "<h1>Something</h1>";
    }
}

People tend to name these Sinatra clones after Rat Pack members, but I wanted to be different, so called it the first name that came into my head.