Javascript: The Underappreciated Dynamic Language

Posted by Maciek Sun, 13 Aug 2006 04:19:29 GMT

I’ve always felt that Javascript is an under-appreciated language.

This is probably due to the fact that it’s been cursed in several tremendously unfortunate ways: First, Javascript has always been associated with Java, with which it shares pretty much no characteristics, leading to some undeserved lumping-with and confusion when it comes to the things that Java does badly within web browsers; Second, Javascript is a deceptively “easy” language that doesn’t initially appear to have much to it – many programmers (even ones with academic backgrounds) use it as if it was a vastly-weaker cousin of Java and for whatever reason never chance upon Javascript’s fascinating high level features; Third, Javascript appears to be “missing” a lot of features that were hip and happening through much of the crazy dot-com days and the last few years IT in general—object-orientation in the pop sense being one of them; Fourth, and most frustratingly, for many years the web and print resources available to anyone interested in the true nature of Javascript have been disgustingly atrocious and juvenile. (One might argue that this is changing nowadays with the focus on AJAX, increasing prominence of dynamic languages like Ruby, and the surging interest in LISP-like features, as evidenced by nearly every language gradually incorporating bits and pieces of LISP features into successive versions). For much of the last decade, however, any search engine query for Javascript-related terms has resulted in a barrage of junky websites with little information and a lot of cut-and-paste code for producing animated HTML effects.

To really move forward, we need to stop looking at Javascript as “C for the Web” or worse, “Crappy Java”, and instead try to interpret the language through the lens of what we’ve learned from Ruby, LISP, Scheme, Eiffel, etc. In other words, we’re asking the question: what can we squeeze out of our Javascript experience if we enter the scene expecting features we’re used to in super high level languages? To that end, what follows is a short demo of how we can extend, manipulate, and otherwise tinker with Javascript functions.

Playing with Javascript Closures

We can actually think of Javascript functions as objects. These bear some resemblance to closures, which are a programming feature available in languages such as LISP and Eiffel. Consider the following code contained somewhere within a script:

function bob (a,b,c)
{
  alert(a + b + c);
}

In C, such a function would be compiled as a series of instructions somewhere in memory and that would be that. In Javascript, though, the above code is actually the same as if we have written the following code:

var bob = function (a,b,c)
{
  alert(a + b + c);
}

We can draw a distinction here by clarifying that there is at no time any ‘function bob’ present in our program. In fact, there is a variable bob which happens to presently refer to a function object which when called will execute the code:

alert(a + b + c);

Okay, so what?

Well, when you call some function bob you’ve added to a Javascript program, what you’re doing is telling the Javascript interpreter to call the code referred to by a variable which only potentially refers to a function. This is done by adding parentheses to the end of the name of the variable that points at the function, like so:

bob()

Quite elementary stuff. Call the function that bob refers to, and do so because I put parentheses after its name. Now consider that we can create another variable that points at our function:

var a = bob;

Here we’ve told the interpreter that we want a new variable ‘a’ which refers to the function referred to by variable bob. We can call ‘a’ as before:

a()

So in Javascript, functions appear to be portable and mostly anonymous except that for the most part (in day to day usage) we agree to refer to them via the same names, over and over again. In popular usage, we rarely see any other kind of usage pattern. You can also see that a variable which refers to a given function can become null or eventually come to refer to some other function, or even some other object. Below you’ll see that we can pass functions to other functions and execute them in an anonymous fashion:

var f1 = function(a,b)
{
  return (a + b);
};

var f2 = function(a,b)
{
  return (a * b);
};

...

function call_f(f,x,y)
{
  alert(x+" ? "+y+" = " + call_f(x,y));
}

call_f(f1,1,2);
call_f(f2,1,2);

Feeding f1 (an adder) to call_f will first produce the result 1 ? 2 = 3. We then give it f2, which is a multiplication function, which gives us 1 ? 2 = 2. The overall effect is that we can carry around and dynamically involve functions and feed them to functions which are not aware of or don’t care about the specific function they use, but need to be able to do so dynamically.

Extending call_f to a Generalized Caller

Ideally we’d like to be able to extend call_f to be able to take any function and feed it any number of arguments. This is useful if we want a generic piece of code that feeds an unknown given set of arguments to a closure (i.e. function) that takes an unknown number of arguments and uses the result. This seems a bit weird and difficult at first until we recall that Javascript allows us to extend pretty much any object with fields that contain other objects.

Of course, in Javascript, functions are objects too and are therefore extendible. Recall that we were able to create a function by creating a variable that points to one:

var a = function() { ... }

Also recall that in Javascript we can add a field to any object with the dot notation without having to predefine a ‘class’:

var orange = new Object();
orange.radius = 5;

Since Javascript functions are also objects, let’s go ahead and extend a function:

var addnum = function(a,b)
{
  alert(a + b)
}

// add a function call_self to addnum
addnum.call_self = function(x,y)
{
    this(x,y);
}

We are now ready to create a generalized version of call_f. We want to use it in the following form:

call_f(f,[p1,p2, ... pn]);

The above code takes a reference to function f and calls it as if we executed the following code:

f(p1,p2, ... pn);

The reason why we want to be able to do this is so that we can gain some of the benefits we’ve seen in languages like Eiffel. In the Eiffel language it is possible to hold onto a function for a while, prepare some arguments for it and call it with those arguments at will (strictly speaking, with closures it’s also possible to predefine or ‘close’ some, all or none of the arguments p1 .. pn). Here is the final version of our call_f function in all its glory:

function call_f(f,args)
{
  f.call_self = function(ars)
  {
    var callstr = "";
    for(var i = 0; i < ars.length; i++)
    {
      callstr += "ars["+i+"]";
      if(i < ars.length - 1)
      {
        callstr += ',';
      }
    }
    eval("this("+callstr+")");
  };

  return f.call_self(args);
}

The function call_f now takes a function and extends it with a more sophisticated version of our call_self function. The call_self function scans through its own ‘ars’ argument (which from our desired call syntax will be an array of the arguments which we want to pass to function ‘f’) and builds a string that when evaluated will have the general form:

this(ars[0], ars[1], .. ,ars[n]);

Since ‘this’ in this case refers to the function that ‘call_self’ is a member of, calling call_self with an array will result in calling ‘this’ with arguments that are the exploded version of that array, each in its proper position within the parentheses.

We can now begin to use functions in a closure-like way in Javascript:

function mult(x,y,z)
{
  return x * y * z;
}

call_f(mult,[1,2,3]);

“Closing” some of the arguments in true closure style is left as an exercise to the reader.

Posted in  | Tags , , , ,  | no comments | no trackbacks

Trackbacks: 0

Use the following link to trackback from your own site: http://schf.uc.org/articles/trackback/241

Comments: 0

Leave a response | RSS feed for this post

Leave a response

Toggle website and email fields