As described in detail previously, I've recently taken part in the JS1K competition where you have to squeeze something cool and clever into 1024 bytes of JavaScript. The quest to condense has become quite addictive and I found myself obsessing over every byte. This is the kind of stuff that the Closure Compiler does quite well automatically but there are some cases where you just need to get in there and manually tweak.
Here are some of the tricks I've picked up in my struggle for extreme minification:
Basic improvements
Use short variable names.
This one's fairly obvious. A more useful addition to this is:
Shorten long variable names.
If you're going to be accessing an element more than once, especially if it's a built-in element like 'document', you'll save a few bytes every time you reference it if you create a shortened reference to it.
document.body.style.overflow="hidden"
document.body.style.background="red"
(74 characters)
can shorten to
d=document;b=d.body;s=b.style;
s.overflow="hidden";
s.background="red"
(69 characters)
and any references to s
after are going to save 19 characters every time.
Remove whitespace
This one's so obvious, I don't need to mention it.
Set Interval
The extremely handy setInterval
function can take either a function or a string. If you give it an anonymous function declaration:
setInterval(function(){x++;y--},10);
You will use up more characters than if you give it just the inside of the function as a string:
setInterval('x++;y--',10);
But the outcome will be the same.
Little-used aspects
Not many people use JavScript's scientific notation unless they're doing scientific stuff but it can be a great byte saver. The number 100
is equivalent to 1 * 10^2
which is represented in JavaScript as 1E2. That's not a great saving for 100 but 1000 is 1E3, 10000 is 1E4. Every time you go up a factor of 10, you save 1 byte.
Fight your good style tendencies
In the war against space, you have to bite the bullet and accept that you may need to sacrifice some of your hard-earned practices. But only this once. Don't get in to the habit, okay?
No zeroes
0.5 = .5
Yeah, it looks ugly but it works and saves a byte.
Naked clauses
if {
:
:
} else y
The y
looks so naked out there. No braces to keep it warm. But if you only have one statement in your else clause, you don't need them...
No semi-final. . . final-semi. . . Semi-colon. No final colon.
You don't need a semi-colon on your last line, even if it does make it look as though you've stunted its growth.
The final few bytes
Operator precedence
You don't need brackets. Brackets are handy for you as the programmer to remember what's going on when and to reduce ambiguity but if you plan correctly, most of the time you won't need brackets to get your arithmetic to work out.
b.getMilliseconds()/(a*250)
is the same as
b.getMilliseconds()/a/250
Shorthand notation
l=l+1;l=l%14;
l++;l%=14;
l=++l%14;
The three lines above are equivalent and in order of bytes saved.
Shorthand CSS
If you need to set some CSS values in your script, remember to pick the most appropriate short form. Instead of s.background='black'
, use s.background='#000'
but instead of s.background='#F00'
, use s.background='red'
. In the same vein, the statements margin="0px"
and margin=0
mean the same but the latter saves bytes.
Don't be generic
One final thing to mention is that these little challenges are not the norm. If you find yourself trying to squeeze code down like this you're probably working on a very specific project. Use that to your advantage and see if there are any savings to be made by discarding your usual policies on code reuse. In the JS1K challenge, we're provided with a specific HTML page and an empty script tag. One good saving made here (and mentioned in my previous post) was the way I grabbed the reference to the canvas element. The standard method is to use the id assigned to the canvas.
d.getElementById('c')
Which is a good generic solution. No matter what else was on the page, no matter what order stuff was in, this would return the canvas. However, we have a very specific case here and the canvas is always going to be in the same place - the first child of the body element. That means we can do this instead:
b.children[0]
This makes use of the reference we grabbed to the body earlier. If the page were rearranged, this would stop working but as it won't, we've saved 8 bytes.
In conclusion
Yes, this is all quite silly but it's also fun and tricky. Attempting these kinds of challenges keep us developers mindful of what it is we actually do and that makes it an extremely productive silly hobby.