Sunday, September 23, 2012

Immediately-invoking functions with an exclamation point in JavaScript

Recently I had to make use of Twitter buttons and I noticed something particularly interesting in their bootstrap code:
!function(d,s,id){var ... }(document,"script","twitter-wjs");

What's interesting to note here is this incantation:
!function () {


Notice how this looks awfully familiar to how one would normally express an immediately-invoked function:
(function () {


In fact, they are fundamentally doing the same thing, yet the former is a byte shorter.

Note that this technique can be accomplished with the other unary operators as well:

What's happening here is that the unary operators are turning a function declaration [function () {}] to a function expression [!function () {}], which can then be immediately-invoked.

One limitation to using this method is that you can't get back the output of the function, unless you are expecting a truthy/falsy value.

This is because the return value is coerced to a boolean when using the exclamation point and negated (since the function invocation has higher precedence, which is why this technique works), and you can't undo that boolean coercion operation on complex types, strings and numbers.

You can however undo the negation operation if you are expecting a truthy/falsy value by simply double negating the output: var truthy = !!function () { return 1; }();

Webroulette: Take me somewhere random!

So once again, what follows is the result of a weekend-project-during-the-week kind of thing.

Similar to where you shuffle through random people, I wrote this so that you can shuffle through random websites instead:

You can also specify a single word to be used as a form of bias:

You can see it in action here:

Source code

As usual, the source for this project resides on github.

How it's done

In a nutshell, I basically do a Google Custom Search API call with a randomly constructed query and then show the first result from the collection of hits.

The server
On the server, I have a file of ~8.5k commonly used English words, and based on the length query string value, I select a number of these words in a random manner.

Note that I enforce a hard limit on the range for the allowed values of length; currently, the range is [0, 10]. If no length is specified, I default it to 3.

This is the word-list that I'm currently using is at

If a bias is specified, I use it as the first word in the phrase and once this phrase is built, it's echoed so that it can be read by the client.

Here are some examples of the script in action:

The client
So what the client does is an Ajax call to this PHP script to get the query and then do an Ajax call to the Google Custom Search API to get a list of hits. Btw, I'm also using a query string which I termed iesux which I use for a unix timestamp, and I had to do this because calls to the same url were being cached by Internet Explorer and so I needed this timestamp to introduce variety to the urls.

What I then show on screen is the first result from the list of google hits from that query.

Why not embed an I'm Feeling Lucky link in the iframe?
Halfway during the project, I realized that this functionality is pretty similar to the I'm Feeling Lucky functionality that Google still offers (for some reason?).

I figured that this way, I would eliminate the need to use the API (which, btw, has a 100 queries a day limit) but instead use an I'm Feeling Lucky url (like for the source of the iframe.

But after I tried a couple of queries like this, I realized that sometimes, an I'm Feeling Lucky url redirects to an actual Google Search page and since Google prevents their site to be rendered in an <iframe>, I was getting a lot of blank pages in the <iframe>...and that sucks.

What about the 100 query limit?
For the free offering of the Google Custom Search API, Google enforces a 100 queries per day (per project) limit.

To work around this, I created five projects (i.e. 5 API keys) and whenever someone loads the page, I serve one of the five keys at random. If it turns out that that particular key is used up, the client requests another API key.

You can also specify your own API key (make sure your that the the Custom Search API service is turned on) using the key query string, as follows: