Hacker News new | past | comments | ask | show | jobs | submit login
Byte-saving techniques in JavaScript (github.com/jed)
112 points by jedschmidt on May 22, 2011 | hide | past | favorite | 22 comments



I hope everyone is upvoting this just for science. DON'T use these all the time, leave this job for a minifier and focus on maintainable code.


I think this is meant to be a fun project that gets people to learn some of the quirks in the Javascript language. It reminds me a little bit of code obfuscation contests: the more deeply you understand the language, the better you will do. The advantage here is that it's not intentionally misleading and actually could be useful.


This is a good point. If you're going to write minified code like this, you should at least annotate it liberally like this example:

https://gist.github.com/962814


I agree... some of them are handy tricks that don't make the code obfuscated or less readable, but not all. Some people think code like this is clever or desirable, too. Also, I've actually seen code in jQuery plugins such as

    if(condition)
     //{ //save a byte!
       action();
     //} // save a byte!
as if leaving out the braces will actually make your code run faster, or make a real difference after minification. I could easily see that sort of person thinking this article is like an elite JavaScript style guide.


"Byte-saving" made me think more of memory management than source file size.

Since version 1.5, JavaScript accepts Unicode characters as identifiers. Shouldn't this be "character-saving"?


This is aimed at people writing tweet-sized JavaScript for http://140byt.es/ . This is a great resource for learning JavaScript and has some very impressive code behind it. Generally for production sites, though, I'd much rather go with jQuery due to its extensive test suite and bowser support. Between tweet-sized and jQuery-sized JavaScript, there's a whole lot of micro JS scripts / frameworks on http://microjs.com/

I'm currently writing a mobile web app that needs to work over GPRS connections with 30kb/s bandwidth and up to 1s latency. In these cases, shaving off a few bytes to get a page in 1 fewer TCP/IP packets really does make a difference.


Good lord, I'm pretty sure no-one is suggesting you use these in production. In fact it says at the top you shouldn't.

If you are writing mobile apps you should check out XUI instead of jQuery. jQuery (even jQ Mobile) is super heavy. XUI is jQ like, but it is by the Nitobi guys (of PhoneGap fame) and they really get mobile and did it right.


A lot of these tricks _are_ used in production, the result of uglifyjs/closure minification of otherwise sane code. This is just a guide for hand-tuning.


I love doing stuff like this for fun. Sometimes I try to get nice algorithms into tweets. Here is one of my favorites so far, returns the powerset for array 'a':

            function P(a){for(p=[],i=Math.pow(2,l=a.length);i;)for(b=i.toString(2),j=k=b.length,p[--i]=[];j;)if(b[--j]==1)p[i].push(a[j+l-k]);return p}
I know that there are some big gotchas here, such as b and p being declared globally due to lack of var...but I gave up trying to gain an extra 4 bytes for function(a,b,p). Also the subset arrays are in reverse order.


There's a lot of room in there:

    Math.pow(2,l=a.length)
    1<<(l=a.length)
are the same, as are these:

    if(b[--j]==1)
    ~-b[--j]||


Thanks! This is an amazing guide. I forsee many more lost hours shaving and shaving with this in hand.


Just remember to fork the master gist (https://gist.github.com/962807) when you're done, and add an annotation so that the rest of us can learn from it!


  rand10=Math.floor(Math.random())*10 // before
  rand10=0|Math.random()*10           // after
The first is not random, it will always return zero (this error is very common). The second happens to be ok because * binds tighter than |. However, this is order-dependent.


Oops, that was an error (the multiplication should be within the .floor call). It's fixed now.

This style of code, while not for everyone, exploits the "happens to be okay" operator precedence. For this, Mozilla's MDC is a great resource:

https://developer.mozilla.org/en/JavaScript/Reference/Operat...


Hah. Wish I'd thought of some of these for last year's http://10k.aneventapart.com .

I tried to write most of my JS for 10k 'pre-minified', using tricks akin to (but not as awesome as) these. Echoing other commenters, it was largely as an intellectual exercise (to see if I could meet the 10k limit by hand) but it did make me think of a few things in a different light, and some of the 'optimizations' are things that minifiers wouldn't have done for me.

It's also a good way to get under the skin of a language, get a feel for the nuances of how the runtime behaves, and give you hints for other (more generally useful) optimisations.


It's also interesting to see how the approaches differ at each order of magnitude from 140byt.es to JS1K to 10K Apart.

At the smallest end you really have to work with what you're given and triage fast, whereas with JS1K you see people writing decompressors _in_ their code to get around JavaScript's occasional verbosity.


Shouldn't minifiers worry about all this stuff?


Generally yes, but sometimes it's a fun intellectual challenge to squeeze a piece of code as small as possible. Humans can also make assumptions that a "safe" minifier can't.


They should also add:

    Math.floor(someNumber) // 2.6 becomes 2
    someNumber | 0         // 2.6 becomes 2
Not only because it saves characters, but because it might actually be used in the real world (Whereas most of the ones in the article should really be left to a minifier)


The problem with this technique is that it will not work for large numbers (in my build of node, for example, the largest number it will work with is 2^31 - 1:

  (Math.pow(2, 31) - 0.1) // base number
    2147483647.9
  ~~(Math.pow(2, 31) - 0.1) // works!
    2147483647
  (Math.pow(2, 31) + 0.1) // base number
    2147483648.1
  ~~(Math.pow(2, 31) + 0.1) // doesn't work!
    -2147483648


That's already covered, along with use of ~~ for the same purpose.


Oops, sorry. I must have misspelled 'floor' on my CTRL-f




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: