How I Learned JavaScript

The thing with JavaScript is that no-one learns it. Everyone just jumps in (these days with copy-and-paste jQuery plugins) and struggles to take that knowledge further and learn more about the language. In this post I’ll describe my the key moments I’ve had (“JavaScript epiphanies” if you like) while learning; hopefully someone looking for the next step will have an idea about the next thing to learn.

Everyone learns at different rates and speeds; just because I learned in this order doesn’t necessarily mean that you will. (I’m not 100% sure this is even the order I learned it all in.) This also took me a while to figure out – I’ve been learning this for about 10 years.

Cool – I just wrote my first piece of JavaScript!

The first step: I’ve written something in a programming language – and it works! :D it’s a very different animal from HTML and CSS, far more expressive, far more powerful and far, far cooler.

Oh, I can just type literals…

When I started, the tutorials were full of examples of making an array. They all looked like this:

var myArray = new Array(4);
myArray[0] = 'zero';
myArray[1] = 'one';
myArray[2] = 'two';
myArray[3] = 'three';

The number 4 in the Array constructor is the length and each index has to be put in one at a time. After a while, I realised there was a much quicker way of doing the same thing:

var myArray = ['zero', 'one', 'two', 'three'];

There are similar tricks possible with Objects and suddenly my code was smaller and faster to type. I feel like more of a coder now!

Ah – scripts should be seperate from markup

I used to write code like this:

<body onload="init()">
<form onsubmit="return validate(this)">
<a href="#" onclick="coolStuff(); return false;">

I thought it was the only way to connect elements with scripts. After reading enough times that you could seperate the two, I never looked back. Suddenly the phrase “progressive enhancement” made sense (although we didn’t have a name for it then).

But wait a second, my arrays and objects were verbose, my scripts should be apart from my markup…

That’s the old way of doing it?

I used to use this sort of syntax to get a certain form:

var element = document.forms.formName.fieldName;

I haven’t used this syntax for so long, I actually had to look it up to make sure I got it right. I found that there are better ways to find elements. The following methods are so much better and faster:

  • document.getElementById
  • document.getElementsByName
  • document.getElementsByTagName
  • document.getElementsByClassName
  • document.querySelector
  • document.querySelectorAll

The next three probably happened in this order, they’re all important and they’re all different epiphanies but somehow they all seem to blend into 1:

I should avoid global variables

They’re slow, interfere with other scripts on the page and they make it harder to write my own functionality.

This is the “module pattern”

That’s how to contain scope, that’s how to create those funky libraries I keep seeing.

And that’s how you minify JavaScript!

I remember seeing things like SWFObject and wondering how they could possibly write code like that. It’s obvious now that they don’t, they write normal code with comments and white-space, indentation and sensibly named variables. They then use minifiers to reduce the code.

This is an epiphany in itself because it completely changed the way I coded. Even now I still make my code just a little more verbose to aid minification. Key things I changed were:

  • All my variables are declared in one place, comma-seperated
  • My code is well commented because comments are removed
  • Anything I do more than one becomes it’s own function or variable
  • I limit my keywords – only one var statement per function, only one return

I started minifying everything I wrote. Sometimes that caused errors though…

(If you’re at this stage and you want a good minifier, I recommend Dean Edwards’ Packer – avoid the Base62 encoding, but shrink your variables.)

JSLint doesn’t always hurt my feelings

Douglas Crockford’s ideas about simplifying JavaScript and only using a subset of it really registered with me. When he started describing JSLint, I tried using it. It hurt my feelings. I tried this piece of code, something I knew was fine, and it found problems with it:

window.onload = function() {
    alert('hi');
}

I was enraged at first, what the hell could be wrong with this – it works in all the browsers! But when I started learning to minify my code, I started running it through JSLint to see what was wrong, it found things like missing semi-colons. Things like this cause huge problems when minified:

var foo = document.getElementById('foo')
foo.onclick = function () {
    alert('hi');
};

Minified, it looks like this:

var foo=document.getElementById('foo')foo.onclick=function(){alert('hi');};

The bit in the middle, getElementById('foo')foo is a SyntaxError. It’s tough to spot when you’ve got a lot of code, but put the example into JSLint and it’ll tell you exactly which semi-colon I missed. The realisation that JSLint is actually useful was a huge step forward in my programming career.

Somewhere around the 3 close epiphanies I learned another important thing…

Functions can be reusable

I started breaking common tasks down into functions. Anytime I did something more than once I’d put it in a function and simply call it. An if statement or two could give me different results. It became a hugely useful trick and actually reduced the size of my code.

I think this trick above all others taught me how to properly work with events. Any combination of events that did the same thing would simply call the same function, sometimes with exactly the same parameters. My code felt more reusable and robust.

The DRY method – Don’t Repeat Yourself

It turns out this is a mantra that some programmers live by. When I’d learned how to reuse my functions, I learned how to write all my code so I didn’t repeat any functionality, I just called the same function again.

Event delegation

With not repeating myself and reusing code I learned how to delegate my events. This is more of a DOM epiphany than a JavaScript one, but it took everything you’ve read so far to really understand how easy event delegation is.

Incidently, if you’re at the stage where you want to do this:

for (var i = 0; i < links.length; i++) {
    links[i].onclick = function () {
        alert('I am link number ' + i);
    };
}

and you're wondering why every single link thinks it's the last one, event delegation will solve that problem completely.

To fix a problem, one must first detect the problem.

I used to browser-sniff. If you're unfamiliar with the technique, it's where you ask the browser what it is and give it different code depending on what it tells you. The only problem with this is that browsers lie. I'd read a few things about object detection (some simple and some advanced) and it all lead me to the conclusion that's currently sitting at the top of this section in bold. You have to be able to detect a problem in order to fix it. Browser-sniffing may get the job done by the deadline, but if you want solid code that will work on any browser, you have to be able to check whether or not it understands it. Techniques like this can lead to very useful tricks like shims to add missing functionality.

Functions should only do one thing.

This is something that I've only ever seen mentioned in one place but when I learned it, it completely transformed my code. Ever since learning this, my code is a lot more modular. I now have a lot more functions and some of them simply call collections of other functions. It makes my code far easier to debug because I know where to look for a certain action.

At first I found it curious, but the way I created functions completely changed when I started doing this. (Now I find it very useful and I'll explain why a little later.) Whereas I used to define functions as a list of statements, now I create objects with methods, the object name helps contain the functions logically and make it much easier to see where they are. I'll show you what I mean - here's something that seems to find it's way into most of the things I write these days:

var toString = Object.prototype.toString,
    is = {
        array: function (o) {
            return toString.call(o) === '[object Array]';
        },
        callable: function (o) {
            return toString.call(o) === '[object Function]';
        },
        numeric: function (o) {
            return (toSting.call(o) === '[object Number]' || (is.string(o) &&
                o !== '') && !isNaN(o));
        },
        string: function (o) {
            return String(o) === o;
        }
    };

All my type-checking functions are contained within the is object and each of them do a single thing. It's not a coding style I thought I'd adopt but it instantly made sense when I started writing a lot of simple functions.

This style opened up my understanding of RequireJS - instead of thinking of scripts as script tags, I started thinking of them in terms of modules and objects that I could bring in remotely. This way of thinking is what RequireJS was built for and almost at once I want to use this library more.

The style has one more advantage:

That's how prototypal inheritance works!

I'd been staring at the new keyword and reading all the tutorials I could find, I just couldn't wrap my head around it. I kept trying, but it made no sense at all. Although I've played with other languages before, JavaScript was the first one I really got to grips with. Maybe if I'd played with other languages, Java or C++, I'd understand what the new keyword was trying to do. Luckily, JavaScript's prototype inheritance is far easier to understand now we have Object.create():

var foo = {
        one: 1,
        two: function () {
            alert('two');
        }
    },
    
    bar = Object.create(foo);
    bar.three = 'three';

// This is what we have now:
foo.one; // The number 1
foo.two; // A function that alerts 'two'

bar.one; // The number 1 (gets it from foo)
bar.two; // A function that alerts 'two' (gets it from foo)
bar.three; // The string 'three'

// Manipulating bar has no effect on foo.
foo.three; // undefined

// We can overwrite any property we got from foo.
bar.one = '1'; // Now bar.one is a string.
foo.one; // Still a number, this hasn't been changed.

// We can manipulate foo and the changes will automatically happen to bar.
foo.four = [1, 2, 3];
delete foo.one;

bar.one; // Now it's undefined.
bar.four; // An array containing 1, 2, 3

I probably owe you all a better description of this, but if you can understand that, yes - it's genuinely that easy. By using inheritance I don't have to re-write functions. I can create objects that work differently but have a common base. It's object-oriented programming and I'm just starting to learn it.

So what's next?

Honestly, I don't know. This is the fun thing about programming - there's always more to learn.

I hope you've enjoyed this look into how I learned JavaScript. If you're learning it too, hopefully this entry will help you see what's possible, what to learn next and how long it took me. If there's anything in this list that you don't understand and want to know better, feel free to send me a message, comment on this entry or even start a thread on the forum. If you have a blog, why not write up your experiences learning JavaScript, maybe it will help someone?

One thought on “How I Learned JavaScript

  1. I just jumped in and learned what I needed to. I did however find that Codecademy had some really good Javascript lessons for beginners. I was amazed at how I picked up what I needed to know to do what little I needed to do. You’re definitely more advanced than I am but I would recommend their lessons to beginners.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>