A quick guide through how (I, at least) codegolf

Once upon a time, there was a site where there was a ton of JS crud. Unfortunately, some of that crud was “loading images” (despite the fact that there was no reason to, just like there isn't 99% of the time)

So, I wanted to make something that'd let data-src be converted to src quick and easy. I found a stackoverflow answer and figured “wwelp, that's kinda large but it'll do”. Then I thought “meh, could compress it a little”.

var imgEl = document.getElementsByTagName('img');
for (var i=0; i<imgEl.length; i++) {
    if(imgEl[i].getAttribute('data-src')) {
       imgEl[i].removeAttribute('data-src'); //use only if you need to remove data-src attribute after setting src

// 324 characters

This was obviously non-optimal, and the first thing that caught my eye was that comment. We don't need to remove, so out that goes. I also changed the variable names to try and compress a little before I sent it through a minifier.

var i = document.getElementsByTagName('img');
for (var x=0; x<i.length; x++) {
    if(i[x].attributes['data-src']) {

// 188 characters

This was Good Enough For Now™, so I sent it through uglify-js. (Well, some site that used it. Too lazy to npm install.)

for(var i=document.getElementsByTagName("img"),x=0;x<i.length;x++)i[x].getAttribute("data-src")&&i[x].setAttribute("src",i[x].getAttribute("data-src"));

// 152 characters

This cut down the obvious cruft, but...it still needed a little something. Why were we grabbing data-src twice? I changed the left side to set a variable while checking for its validness.

for(var i=document.getElementsByTagName("img"),x=0;x<i.length;x++)(_=i[x].getAttribute("data-src"))&&i[x].setAttribute("src",_);

// 128 characters

Better. But still not good enough. I noticed something: that for-loop took up about half of the code! (66 characters, to be exact)

Obviously, there was a better way — I knew .forEach was a thing, but unfortunately, getElementsByTagName didn't support it by default because it used HTMLCollection (pls fix) so I had to use Array.from.


// 117 characters

I immediately scanned for a way to not use Array.from, and just my luck — querySelectorAll used NodeList, which did support it. (Unless you were on IE, in which case: tough luck)


// 106 characters

Then I realized something. “Wait, does dataset return strings?” I knew attributes didn't, but it was work a try. ...And return strings it did!


// 96 characters

Double digits, baby! ...I then realized that despite that my JS console hadn't been showing querySelectorAll as an attribute of document, it worked just fine. Oops.


// 91 characters

And then I realized “oh wow, I can just set src instead of setAttribute, I am a fool” (technically the stackoverflow answer was the fool, but I was too for not noticing)

Unfortunately, that required me giving something up.

You see, the original compression had been using && in place of if. But if you try to do an assignment on the right hand of an &&, that's invalid. So I had to go back to using if. But as well, using if inside of an arrow function is also incorrect, unless you surround it with brackets.

Fortunately, this still resulted in a net gain. (Or net loss of characters, as it was.)


// 77 characters

And it was still fairly comprehensible after all was said and done! From 324 characters to 77. Whew. That's almost 75% of the length shaved off!

That's...about how I shorten code down. I don't know why I needed to document this but hopefully it helps someone with something. Have fun!