Ce blog a déménagé et parle maintenant uniquement anglais.

This blog has moved and now only speaks English.

blog.floriancargoet.com

See you there!

/home/florian

le blog de florian cargoet : du linux, du web et du logiciel libre



[EN] My entry for the DailyJS “contest”

11 April, 2011 (23:45) | Webdev | Florian Cargoet

Catégorie Webdev : A propos du web, de son contenu, de ses outils...

Last Friday, DailyJS had 5 digital subscriptions to Hacker Monthly to give away. They set up a small one-liner contest:

If you’d like to read more from Hacker Monthly, we’ve got 5 digital subscriptions to give away — worth $29 each! Just post a comment with your favourite JavaScript one-liner, and I’ll select 5 winners.

Thanks to this piece of code, I am the happy winner of one of the subscriptions:

?View Code JAVASCRIPT
(function ___(__){return function(_){return _!='?' && ___(__+_) || __+'!';};})('d')('a')('i')('l')('y')('j')('s')(' ')('r')('o')('c')('k')('s')('?')

In this article, I’ll explain what it does and how it works.

What it does?

If you copy/paste/run it in your favorite JavaScript debugger you’ll see that the weirdly formatted question ('d')('a')('i')('l')('y')('j')('s')(' ')('r')('o')('c')('k')('s')('?') is answered: "dailyjs rocks!"
Yes, this was blatant flattery (even called ass-kissing ;-) ). Well… It worked!

How it works?

To understand it I am going to uncompress this one-liner bit by bit.

Let’s add some new lines and spaces:

?View Code JAVASCRIPT
(function ___(__){
    return function (_){
        return _ != '?' && ___(__ + _) || __ + '!';
    };
})
('d')('a')('i')('l')('y')('j')('s')(' ')('r')('o')('c')('k')('s')('?')

I obviously use the underscore character to make the variable and function names more meaningful. Who wants obscure names like these:

?View Code JAVASCRIPT
(function createAccumulator(allPreviousLetter){
    return function (newLetter){
        return newLetter != '?' && createAccumulator(allPreviousLetter + newLetter) || allPreviousLetter + '!';
    };
})
('d')('a')('i')('l')('y')('j')('s')(' ')('r')('o')('c')('k')('s')('?')

createAccumulator is the best name I could think of but it’s not that good… I really prefer ___.

It’s more readable now but what is this && and || stuff ?

You know what it means here: 

?View Code JAVASCRIPT
if( conditionA && conditionB || conditionC){ }

Since JavaScript is fun, you can use objects instead of booleans and it works since there are such things as truthy and falsy values (“” == false, for instance).

?View Code JAVASCRIPT
if( newLetter != '?'  && someFn() || someString ){ }

What more interesting is that if (A && B) is true, it doesn’t “returns” true but it returns B! You probably use the same feature with || to specify a default value:

?View Code JAVASCRIPT
var a = b || c;

So with all this knowledge it’s easy to translate

?View Code JAVASCRIPT
return newLetter != '?' && createAccumulator(allPreviousLetter + newLetter) || allPreviousLetter + '!';

into:

?View Code JAVASCRIPT
return newLetter != '?'  ? 
    createAccumulator(allPreviousLetter + newLetter) :
    ( allPreviousLetter + '!' );

or more readable:

?View Code JAVASCRIPT
if ( newLetter != '?' ){
    return createAccumulator(allPreviousLetter + newLetter);
} else {
    return allPreviousLetter + '!';
}

Now let’s remove this disturbing Immediately-Invoked Function Expression (IIFE) and these chained function calls.

?View Code JAVASCRIPT
function createAccumulator(allPreviousLetter){
    return function (newLetter){
        if ( newLetter != '?' ){
            return createAccumulator(allPreviousLetter + newLetter);
        } else {
            return allPreviousLetter + '!';
        }
    };
}
 
var accumulate_D_and_return_a_new_accumulator   = createAccumulator('d');
var accumulate_DA_and_return_a_new_accumulator  = accumulate_D_and_return_a_new_accumulator ('a');
var accumulate_DAI_and_return_a_new_accumulator = accumulate_DA_and_return_a_new_accumulator('i');
//…
var lastOne                                     = accumulate_STUFF_and_return_a_new_accumulator('s');
var totalStringWithExclamationMark              = lastOne('?');

Crystal clear now, isn’t it?