Javascript: Consoles and First-class Functions

I’ve been writing a lot of Javascript lately. It’s a lot more fun when you treat it as a real programming language (which it is) and not that horrible thing that’s shoved inside all the browsers. It’s also a lot more fun when you decide that nothing but the most recent versions of Firefox and Chrome exist, which leads me to my first topic.

Javascript Shells

Both the Mozilla and Chrome projects make their Javascript engines available as standalone libraries, which can be embedded in other programs. They also both provide command-line shells which behave just like the Python/Ruby REPL.

Not only is this just plain nicer than using the browser devtools, but the shells add new functions to the language that make it better suited to the console world, like ‘print()’ and ‘load()’, which finally makes it possible to include Javascript from other Javascript files (under the shell). There’s also a good amount of deeper stuff which would be handy for serious debugging, like the ability to lock objects, absolutely preventing any modification until unlocked. Best of all, everything I’ve tried in one has worked in the other, though I admit that I haven’t even tried to try everything — I’ve just been working on what interests me.

One thing you don’t get with the shells is the browser environment. So no ‘window’ object, no ‘document’ object, and none of the methods attached to them, which means no DOM manipulation. This will come up again in about 4 paragraphs.

Mozilla’s Spidermonkey shell is ‘js’, and Chrome’s V8 is (unpredictably, and at odds with at least one doc I found on the web) ‘d8’. Both are available as packages under Arch Linux (and everything else, I’m sure). If you do anything with the web, even for fun, your toolbox will be greatly enhanced by adding them to it. Here’s a link to the Mozilla docs (I haven’t found the Google ones yet).

The second thing I want to talk about is a little bit of fun that I painlessly prototyped using the Javascript shell.

First-class Functions

Javascript has them. All it means is that functions aren’t special in any way; they’re treated just like all other data in the language. This is an incredibly powerful concept, which you can use to do incredibly powerful things. Or just to solve an interesting little problem.

Having written a tiny Javascript test library yesterday, I immediately found myself wanting to use it to test things other than the tiny parser I’d written the day before that. The problem was twofold:

  1. My test library replied on the print() function of the js/d8 shells to report its findings to the world, and this, of course, does not exist in a browser.
  2. The other things I wanted to test do live in a browser, and do tons of DOM manipulation, which doesn’t exist in the shells.

The solution came from remembering that functions are first-class in Javascript. But before I could get around to that, I needed to know how to test for defined-ness in Javascript without generating warnings or errors. Well, I could use the shell to fiddle with that, too.

d8> if (document) { print('doc') }
(d8):1: ReferenceError: document is not defined
if (document) { print('doc') }
^
d8>

Nope. Not like that.

d8> try { document } catch(err) { print('no doc') }
no doc
d8>

Ah. try/catch block. Okay, now I know how to see if I’m inside a browser or not, because that’s the only place that the document object exists. So now I can get around to solving my original problem with, effectively, a one-liner. Before changing my test lib code, I decided to use the shell again to make sure my idea really worked.

1  d8> print2 = print;  
2  function print() { [native code] }
3  d8> print = function(msg) { print2("foo" + msg + "bar") }
4  function (msg) { print2("foo" + msg + "bar") }
5  d8> print("hello, world");
6  foohello, worldbar
7  d8>

I’ve numbered the lines this time for easy reference. On line 1, I assign print to print2. Since functions are first-class, ‘print’ isn’t magical in any way, but is just a label, which points to a piece of data. In this case, the data being pointed to is a compiled function, which does the actual printing. So now ‘print’ and ‘print2’ point to the same function and will (natch) behave identically. Line 2 shows the evaluation of the assignment.

In line 3, I reassign ‘print’ to an inlined anonymous function which takes one argument and calls ‘print2’ (AKA the original, stock printing function), passing it the concatenation of “foo”, the argument to ‘print’, and “bar”. Line 4 is equivalent to line 2.

On line 5 I call ‘print’, which now points not to the original stock print function, but to my anonymous function. Line 6 shows “hello, world” stuck between “foo” and “bar”, exactly as it should be.

Now for the real thing:

try {
    if (document) {
        print = function(msg) { document.write("<div>" + msg + "</div>") }
    }
} catch(err) {
    true;
}

Couldn’t be easier. If my test library is inside a HTML document, ‘print’ will be pointed at an anonymous function which wraps the argument inside a pair of ‘div’s and calls ‘document.write’, plopping it into the document where ever the calling <script> tag is located. One library; one try/catch block; works in a webpage or at the console.

Short URL for this post: http://tmblr.co/Zfw3Qy7ItGUy