Know What You’re Referencing

| Comments

A quick nuts-and-bolts JavaScript thing, starting with a tiny code challenge:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var obj1 = {
  foo: function() {
    return this.name;
  },
  name: 'Kermit'
};

var obj2 = {
  foo: obj1.foo,
  name: 'Miss Piggy'
};

var obj3 = {
  foo: obj1.foo(),
  name: 'Miss Piggy'
};

// What is **this.name**?
obj1.foo();
obj2.foo();
obj3.foo;

Something like this tripped me up because I forgot an elementary thing. Our foo methods reference either a function, or, in the case of obj3.foo, the product of a function. This referencing happens when a compiler gathers source code into an executable program, so obj1.foo and obj2.foo reference the same method. The result of calling this method differs depending on which object does the calling, because this references the calling object.

A simple rule is to look left of the method name at call time, which is an event easily spotted due to the use of parenthesis. In the final object, foo points to the product of a function call, rather than to a function. Notice the object that called foo.

So, here are the answers:

1
2
3
obj1.foo(); // Kermit
obj2.foo(); // Miss Piggy
obj3.foo; // Kermit

Did you get them all right?

Hello Open-Source World

| Comments

Git is a command line tool for saving versions of your project. GitHub is a website. If you so choose, you can put your git repositories on GitHub and make them public. This momentous event mightn’t give you an immediate community around your code, but it will mean you’ve joined the open-source world.

The open-source community democratised ownership over code, so that source code published under an open-source license is freely available to everybody to use and/or modify. The antidote to proprietary software owned by corporations, the open-source philosophy shows the tendency for people to continually question the fairness of systems of control and hierarchy. It has even been convincingly argued that open-source programmers needn’t keep their practices for themselves. Their collaborative method can be widely applied for a more democratic and free society:

When Linus Torvalds created Git he embedded the open-source philosophy in that tool. Software development with Git is highly organised, but organised with participation at all angles. Here’s a good overview of how Git can be used by a team of people working on the same files to avoid chaos: What is Git used for? What does it do exactly?

Here’s my GitHub account, which now includes my first repository: github.com/unicodegirl

Using Closure to Fix the Value of i in Loops

| Comments

I’ve been lazy with the blog, and will get back to my intended series on My First API next. Right now, though, I want to tell you about a problem I encountered today, because it was solved with a closure (and a self-invoking function) - that most murky of topics we’ve visited before here and here.

I was practicing abstracting native code - making blocks of code that are easier to reuse - by developing a tiny JavaScript Library. In the roughest sense, I decided to model my tiny library - called tinyLib - on jQuery. Briefly, tinyLib is a function that can accept three types of argument: CSS selectors, DOM elements, and functions. It must identify the type of argument, and deal with it accordingly.

THE ARGUMENTS PARAMETER

All functions automatically have a local variable called arguments, which is an array-like object containing the arguments passed to a function (see Mozilla). The arguments parameter has the property length, which tells us how many arguments are in the collection.

Because tinyLib can take multiple arguments, it’s necessary to loop through the arguments object, to identify and handle each argument according to its type. My script might be a bit rough-and-ready, e.g., typeof arguments[i] === 'function' can produce false positives, and my if-if-if blocks could perhaps be replaced with something more pleasing, but here it goes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for(var i = 0; i < arguments.length; i+=1) {
  if (typeof arguments[i] === 'string') {
    domElements = document.querySelectorAll(arguments[i]);
    for (var y = 0; y < domElements.length; y+=1) {
      elements.push(domElements[y]);
    }
  }

  if (typeof arguments[i] === 'function') {
    document.addEventListener('DOMContentLoaded', arguments[i]);
  }

  if (typeof arguments[i] === 'object') {
    elements.push(arguments[i]);
  }
}

THE PROBLEM

Any code that relies on the DOM must be executed after the DOM has fully loaded - otherwise we run into problems. With jQuery, you pass a function that jQuery executes only once the DOM has loaded. I wanted to mimic that behaviour in tinyLib:

1
2
3
if (typeof arguments[i] === 'function') {
  document.addEventListener('DOMContentLoaded', arguments[i]);
}

As you can see from this snippet, I was trying to pass the function as the callback to addEventListener. This was not working and after some testing I discovered that arguments[i], rather than pointing to a function, was undefined. The DOMContentLoaded event should trigger a callback but arguments[i] wasn’t referencing one. I had to work out why.

When a callback is bound to an event, its execution is delayed until that event has occurred. The event occurs asynchronously, at some unspecified point in the future. Meanwhile, the program continues running. In our case, the for loop continues to cycle through our arguments object until the condition i < arguments.length is satisfied. Remember, arrays are indexed from 0, so our for loop starts at 0 and exits when the condition is no longer true.

If there is just one argument, then the for loop exits when i === 1. Similarly, if there are two arguments, then the for loop exits when i === 2, and so on… The point of all this is time elapses, and by the time the DOM finishes loading, and addEventListener calls its callback function - the anonymous function passed to it - then the value of i is always the last value stored in it, which is one more than the index value of the last item in the collection. Oops!

We need to preserve the value of - rather than the reference to - i at each iteration of the for loop, and that requires a closure.

PRESERVING THE VALUE OF i WITH CLOSURE

Consider the code below, to see how we can control our context - and fix the value of i - with a closure. We’ve added a self-invoking anonymous function inside our for loop that encapsulates our code for identifying and handling each argument passed to tinyLib. We pass to this self-invoking function, the value of i at each iteration, as well as tinyLib’s arguments object, defined as n and args respectively within the self-invoking function. In this way, the value of i is preserved at each iteration as n. We also preserve tinyLib’s arguments object as the value of args, since the self-invoking function has its own local variable called arguments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for(var i = 0; i < arguments.length; i+=1) {
  (function(n, args){

    if (typeof args[n] === 'string') {
      domElements = document.querySelectorAll(args[n]);
      for (var y = 0; y < domElements.length; y+=1) {
        elements.push(domElements[y]);
      }
    }

    if (typeof args[n] === 'function') {
      document.addEventListener('DOMContentLoaded', args[n]);
    }

    if (typeof args[n] === 'object') {
      elements.push(args[n]);
    }

  }(i, arguments));
}

I read about this application of closures in John Resig’s book, ‘Secrets of the JavaScript Ninja.’

The JSONP Hack

| Comments

We skipped over the JSONP hack in the last post (My First API: Fetching and Displaying Tweets). This post takes a look at what happens in the background when we use JSONP.

We previously used jQuery’s getJSON method to request data from twitter’s server - just give getJSON a URL and it requests data for you. Our endpoint URL contained two parameters:

  1. The search query, q
  2. The callback, callback

Here’s the same endpoint again:

http://search.twitter.com/search.json?q=cats&callback=?

We included a callback parameter to make use of the JSONP hack. Otherwise, getJSON requests the data we’re after using XMLHttpRequest - a very sophisticated JavaScript object that’s more powerful but also more law abiding than JSONP.

XMLHttpRequest is subject to the same-origin policy. For security reasons, browsers block data requests made to third-party domains (i.e., domains other than the domain hosting the web page). So, if a page originates from Server X it shouldn’t make a request to Server Y. As Cross Origin Resource Sharing (CORS) limits the security issues that were once present, XMLHttpRequest may soon be the default for cross-domain API requests, but for now we still need JSONP to get over this security hurdle.

The JSONP hack uses the script tag’s security pass. Surprisingly the script tag is not restricted by the same-origin policy, so it can request and execute JavaScript from any server. This is a great benefit in our era of information sharing across the internet.

If we were to write our own version of getJSON, then it might go something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  var myGetJSON = function(endpoint, callback) {

    // Create a script tag.
    var script = document.createElement("script");

    // Create a unique random string of characters to be used as a
    // function name. We don't want to clash with any existing
    // function names.
    var functionName = Math.random().toString(36).substring(7);

    // Set the value of the endpoint's callback parameter to functionName:
    // "http://search.twitter.com/search.json?q=cats&callback=?"
    // becomes
    // "http://search.twitter.com/search.json?q=cats&callback=randomString"
    endpoint = endpoint.replace("callback=?", "callback=" + functionName);

    // Set the script tag's src attribute to the endpoint.  
    script.src = endpoint;

    // Dynamically create and attach to the window object
    // a new method with the same name as the callback parameter.
    window[functionName] = function(data) {
      // NB DATA PASSED TO THE myGetJSON CALLBACK
      callback(data);
    };

    // Append script tag to webpage body
    document.getElementsByTagName("head")[0].appendChild(script);

  };

  // TO TEST:
  myGetJSON("http://search.twitter.com/search.json?q=cats&callback=?", function(data) {
    console.log(data);
  });

As soon as the script tag is appended to the body, the browser calls the endpoint. A JSONP savvy API will look for the callback parameter in the endpoint. That is the indicator the client is expecting a JSONP response. The server responds with an invocation of the dynamically created method (named the value of the callback parameter), passing the JSON object:

1
randomString({load of tweets});

My First API: Fetching and Displaying Tweets

| Comments

My challenge to myself this weekend was to tackle my first API - twitter’s search API. I’ll break down my process into five blog posts: (1) fetching and displaying tweets, (2) templating with Handlebars, (3) adding a search field to find tweets, (4) using JavaScript’s timer - setInterval - to update tweets, and (5) using regular expressions to create links in tweets.

I wanted to get to the heart of things, without getting lost in too much information. These posts are about taking some big (for me anyway) first steps. I chose twitter’s search API because it doesn’t require any authentication. I’m using jQuery’s getJSON method.

STARTING AT THE ENDPOINT

getJSON always requests a JSON object for us to play with. It takes two parameters: an endpoint or resource URL, and a callback function. The endpoint / resource URL refers to a URL that points to a web service that returns data. There’s no website at the end of this URL, but rather data - the JSON object we’re after. This is what the getJSON method looks like:

1
2
3
$.getJSON(url, function(data) {
  ...
})

Looking at the first parameter, twitter’s search API documentation gives us the following Resource URL:

http://search.twitter.com/search.format

It took me a while to twig, but obviously we need to add the correct format - .json - and build our resource URL from there. Starting at the beginning, a resource URL is generally built from the following parts:

  1. The domain
  2. The path (follows the forward slash)
  3. The format, e.g., .html (requests markup) and .json (requests JSON)
  4. ? (separates the parameters from the rest of the URL)
  5. The parameters (name-value pairs separated by an ampersand, &)

Twitter’s resource URL has one required parameter - your search query, named q - but, since we want to use the JSONP hack when we make our request, we also need to add a callback parameter. At this point, we probably don’t need to worry too much about what the JSONP hack is; just understand it’s a clever way for us to get around the same-origin policy. Here’s our resource URL for querying twitter’s search API for tweets that include the word cats:

http://search.twitter.com/search.json?q=cats&callback=?

THE getJSON CALLBACK FUNCTION

The second parameter in our getJSON method is a callback function. A callback function is so named because, at some convenient time, e.g., when it’s finished speaking to an API, the function you’re passing it to will call it (back). Callbacks are used widely in JavaScript. The callback passed to getJSON should not be confused with the callback parameter in our resource URL (see above), which is used by the API service as part of the JSONP hack.

The request made by getJSON happens asynchronously, meaning the programme continues immediately as getJSON, well, gets JSON. When there is a response from the server, the getJSON callback function is invoked with a JSON object being passed as the argument. We receive this data inside the callback, and it’s there that we have to deal with it. We can either send it to another function, or do something with it there and then. In the following example, we’re iterating over the data.results array of tweets, and prepending the text of each tweet to a list:

1
2
3
4
5
6
7
8
9
$.getJSON('http://search.twitter.com/search.json?q=cats&callback=?', function(data) {

  // NB Another example of a callback: jQuery's each() method takes
  // an array and iterates over that array, invoking the callback
  // function for each item...
  $.each(data.results, function(i, tweet) {
    $('ul#tweets').prepend("<li>" + tweet.text + "</li>");
  });
});

Twitter currently provides the following example of the returned data (note, we have drilled into the data object to access the information we want):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
  "completed_in":0.031,
  "max_id":122078461840982016,
  "max_id_str":"122078461840982016",
  "next_page":"?page=2&max_id=122078461840982016&q=blue%20angels&rpp=5",
  "page":1,
  "query":"blue+angels",
  "refresh_url":"?since_id=122078461840982016&q=blue%20angels",
  "results":[
  {
    "created_at":"Thu, 06 Oct 2011 19:36:17 +0000",
    "entities":{
      "urls":[
        {
          "url":"http://t.co/L9JXJ2ee",
          "expanded_url":"http://bit.ly/q9fyz9",
          "display_url":"bit.ly/q9fyz9",
          "indices":[
            37,
            57
          ]
        }
      ]
    },
    "from_user":"SFist",
    "from_user_id":14093707,
    "from_user_id_str":"14093707",
    "geo":null,
    "id":122032448266698752,
    "id_str":"122032448266698752",
    "iso_language_code":"en",
    "metadata":{
      "recent_retweets":3,
      "result_type":"popular"
    },
    "profile_image_url":"http://a3.twimg.com/profile_images/51584619/SFist07_normal.jpg",
    "source":"&lt;a href=&quot;http://twitter.com/tweetbutton&quot; rel=&quot;nofollow&quot;&gt;Tweet Button&lt;/a&gt;",
    "text":"Reminder: Blue Angels practice today http://t.co/L9JXJ2ee",
    "to_user_id":null,
    "to_user_id_str":null
  },
//  ...
  ],
  "results_per_page":5,
  "since_id":0,
  "since_id_str":"0"
}

JavaScript Patterns & Grokking Closures!

| Comments

Last year I wrote a post on JavaScript closures. Another newbie programmer read that post and emailed to say, yes, that’s nice, but when practically do you use them… fast forward a few months, and I’m finally beginning to grok the beauty of closures myself.

This happened precisely because I started building - then rebuilding - my first app. I have restructured things more than once, in my attempt to investigate and wrap my brain around popular ways of organising code. Along the way, I have discovered the importance of good building blocks, as well as how to use closure to keep the guts of a program tucked away.

Here’s some code for capturing a value and building a list:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$(document).ready(function() {
  // Define list here so available to all methods
  var $list = $('#itemsList');

  // When form submitted...
  $('form#listRandomItemsForm').on('submit', function(event) {

    // Get value
    var $input = $(this).find('input[type=text]'),
        value = $input.val().trim();

    // Add to list if there is an input value
    if (value) {
      addToItemsList(value);        
    };

    // Reset text input field to blank
    $input.val('').focus();

    event.preventDefault();
  });      

  var addToItemsList = function(value) {
    var $li = $('<li />').text(value);

    $list.prepend($li);
  };   
});

This is some pretty trivial code, but we’re going to refactor it anyway, to quickly illustrate the usefulness of two common coding practices. In our examples, we are careful to keep variables out of that most messy of intersections, the global scope - a best practice achieved by all the various coding patterns available to us.

The Building Blocks For Adaptive Code

Plans have a habit of straying from the sketched path. When this happens to your application, change in one area should come easily enough, without unpredictable knock-on effects jumping up elsewhere. Such forward compatibility is greatly more achievable if we break things down into clearly defined packages of reusable code at every step and level of our program. In the following example of the object literal pattern, we define single-purpose atomic parts - the methods - in a containing object literal that groups related units of behaviour:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var ListApp = {

  init: function() {
    // Define list as a property of ListApp, so available to all methods
    this.$list = $('#itemsList');

    // When form submitted...
    $('#listRandomItemsForm').on('submit', function(event) {

      var value = ListApp.getValue(this);

      // Add to list if there is an input value
      if (value) {
        ListApp.addToItemsList(value);
      };

      event.preventDefault();
    });
  },

  getValue: function(form) {
    var $input = $(form).find('input[type=text]');
        value = $input.val().trim();

    // Reset text input field to blank
    $input.val('').focus();

    return value;
  },

  addToItemsList: function(value) {
    var $li = $('<li />').text(value);

    this.$list.prepend($li);
  }
};

// Initialise ListApp when DOM ready 
$(document).ready(function(){
  ListApp.init();
});

For more on the object literal pattern, check out Using Objects to Organize Your Code by Rebecca Murphey.

Disappear Code With Closure

The final example shows how we can use closure to prevent misadventure when a developer interacts with our program. Only an object, which acts as a public API (used by other parts of our application, or even other applications), is returned from a self-invoking function. The returned object is automatically assigned to ListApp, but everything else in the closure is removed from general reach, so the guts of our program are protected. Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  var ListApp = function() {
    // Define list here so available to all methods
    var $list;

    var init = function() {
      // Cache list
      $list = $('#itemsList');

      // When form submitted...
      $('#listRandomItemsForm').on('submit', function(event) {
        var value = getValue(this);

        // Add to list if there is an input value
        if (value) {
          addToItemsList(value);
        };

        event.preventDefault();
      });
    };

    var getValue = function(form) {
      var $input = $(form).find('input[type=text]'),
          value = $input.val().trim();

      // Reset text input field to blank
      $input.val('').focus();

      return value;
    };

    var addToItemsList = function(value) {
      var $li = $('<li />').text(value);

      $list.prepend($li);
    };

    // OUR PUBLIC API
    return {
      init: init
    };
  }();

  $(document).ready(ListApp.init);

The above is an example of the module pattern popularised by JavaScript hero Douglas Crockford. Check out one of his lectures (starts 20 minutes in, at hopefully the relevant bit).

From getElementById to querySelectorAll: JavaScript and the DOM

| Comments

This post presents the JavaScript methods for retrieving element nodes from the DOM: getElementById, getElementsByClassName, getElementsByTagName, getElementsByName, querySelector, and querySelectorAll.

JavaScript evolves. The changes spur browsers to become all the better to support it, and developers to figure out how best to apply it. Here, the Selectors API - querySelector and querySelectorAll - is the newer kid on the block. It lets developers pin down elements using CSS selectors.

You can check out browser support for both older and newer methods here. Let’s take a look at each method in turn, starting with the trusty old getElementById

getElementById

If you know the id of the element you want, the document object’s getElementById is the quickest method in your toolbox. It returns a single element (or else null), e.g.:

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="stockings">
  <ul>
    <li class="edible">Orange</li>
    <li class="edible">Chocolate</li>
    <li>Yo-yo</li>
  </ul>

  <ul>
    <li>Harmonica</li>
    <li class="edible">Strawberry bootlaces</li>
    <li><a name="socks">Socks</a></li>
  </ul>
</div>
1
2
// Returns the div and its contents
document.getElementById('stockings');

querySelector

querySelector also returns a single element, but it takes one or more (potentially complicated) CSS selectors, e.g.:

1
2
3
4
5
// Returns the div and its contents (as above)
document.querySelector('#stockings');

// Returns the list element containing 'Harmonica'
document.querySelector('#stockings ul:nth-child(2) li:not(.edible)');

querySelector returns the first matching element it finds; if there is no match, it returns null. You can call it on the document, or on any element, e.g.:

1
2
3
4
5
6
7
8
// Caches second stocking
var stockingB = document.querySelector('#stocking ul:nth-child(2)');

// Returns the list element containing 'Harmonica' (as above)
stockingB.querySelector('li:not(.edible)');

// Returns the list element containing 'Strawberry bootlaces'
stockingB.querySelector('li.edible');

getElementsBy

The getElementsBy… methods each return a live nodeList of elements matching the passed argument, e.g.:

1
2
3
4
5
6
7
8
9
// Returns a nodeList of all the elements with class 'edible'
document.getElementsByClassName('edible');

// Returns a nodeList of uls / stockings
document.getElementsByTagName('ul');

// Returns a nodeList containing the one element with name
// attribute 'socks'
document.getElementsByName('socks');

A live nodeList is an up-to-date collection of elements - an array-like object that updates on the fly (as the DOM changes).

You can call getElementsByClassName and getElementsByTagName on the document, or on any element, whereas getElementsByName is a method of the document only. An empty nodeList is returned if no elements match your query.

querySelectorAll

Like querySelector, querySelectorAll supports multiple selectors (separated by commas), and you can call it on the document, or on any element, e.g.:

1
2
// Returns an array of elements matching the CSS selectors
document.querySelectorAll('li.edible, [name=socks]')

It returns a static nodeList - a snapshot of how things were when the nodeList was created. This means, if the DOM should change, the result of your query may no longer be up-to-date, so you will probably want to re-query the DOM as and when you need to.

querySelectorAll is a little sluggish compared to methods that return a dynamic nodeList but, once you have it, manipulating a static nodeList might be relatively quick (ref). Most of the time, though, nobody will be the wiser if you do trade a little efficiency for more simplicity, e.g.:

1
2
3
4
5
6
7
8
9
10
11
// getElementsByTagName
var items = document.getElementsByTagName('li');
var inedible = [];
for(var i = 0; i < items.length; i+=1) {
  if(items[i].getAttribute('class')!=='edible') {
    inedible.push(items[i]);
  }
}

// vs. querySelectorAll
var inedible = document.querySelectorAll('li:not(.edible)');

Bubbling in JavaScript: What It’s Good For

| Comments

Following on from the post about JavaScript event handlers, this post focuses on event delegation, a useful technique made possible by bubbling.

Consider the following markup:

1
2
3
4
5
<ul>
  <li>Apples</li>
  <li>Pears</li>
  <li>Bananas</li>
</ul>

There are two ways to register an event listener on the li elements:

  1. Once
  2. As many times as the list is long

We can register an event listener once, on a common ancestor - the ul element would do nicely here - and listen out for events from there. Or, we can register a listener on each li element.

Basically, we have a choice between less work and more work. Bubbling gives us this choice; an event bubbles up the family tree - all the way to the window object - and any of the elements along the way may be instructed to listen out for it.

ONCE AND ONLY ONCE

Once and Only Once is a core principal of software development. An explosion of event listeners in a web page has a cost - a measurable performance loss if lists are long enough / sites are big enough. To keep things peppy (and site visitors happy), it seems we must keep our event listeners to a minimum. Once and Only Once also improves programmer performance.

This is because fewer event listeners means clearer code that’s easier to maintain. We typically set our event listeners as soon as the Document Object Model (DOM) has loaded. If we do things right, we don’t need to worry about attaching event listeners to li elements created on the fly after this point. Here’s a silly example to illustrate:

  • Apples
  • Pears
  • Bananas

Thanks to bubbling, we can listen for click events on newly created grapes li elements the future proof way. Our event listener is set on the ul element, so no worries…

1
2
3
4
5
6
7
var list = document.getElementById('fruits');

list.addEventListener('click', function(event){
  if(event.target.innerHTML === 'Grapes (CLICK ME!)'){
    alert('I love Grapes!');
  }
}, false);

TELL MY PARENTS (AND ANCESTORS)

There may be multiple scripts listening out for events on the same DOM element; if so, we don’t want to be rude and stop up the bubbling action (by calling stopPropagation() on the event object). Telling the parents / ancestors is generally important. What we’ll invariably want to do, though, is prevent the browser from performing its default action. This is how we stop our form (above) from loading a new page whenever Add Grapes is pressed:

1
2
3
4
5
6
7
8
  form.addEventListener('submit', function(event){
    var newLi = document.createElement('li');
    newLi.innerHTML = 'Grapes (CLICK ME!)';
    list.insertBefore(newLi, list.firstChild);

    // PREVENT DEFAULT
    event.preventDefault();
  }, false);

Notice we pass false as the final parameter when calling addEventListener. This parameter, which takes a boolean value, decides whether we’re using bubbling (false), or trickling / capturing (true). Trickling / capturing is bubbling in reverse (top-down). Bubbling makes more sense and is supported by all modern browsers (pre-IE9 browsers don’t support trickling / capturing).

From Inline Events to addEventListener: a Brief Overview of JavaScript Events

| Comments

What follows is a brief overview of event handlers in JavaScript. It’s not meant to be a thorough overview; the aim is to provide a beginner’s look at each event model, so we can understand when we might choose one over another.

It’s now pretty standard to keep document content (markup) and document presentation (CSS) in separate files, but this wasn’t always the case. Prior to the rise of CSS, designers and coders relied on less elegant solutions, e.g., contorting content into place using tables-inside-tables-inside-tables. For web browsers, finding content was like hunting for the smallest matryoshka doll.

It makes sense to organise like with like, so I was surprised to learn you can also muddy content with JavaScript behaviour: The original (and out-of-date) way to register an event handler - a function that’s executed when an event occurs - is to write it inline as an attribute of the HTML element, e.g.:

1
2
3
// As an HTML attribute
<input type="button" value="Hit Me"
  onclick="alert('This feels wrong!');">

This string of JavaScript code - written directly into the HTML tag above - adds an onclick property to a button, so an alert pops up when the button is clicked. This is a simple way to get interactivity into a web page, and web browsers still support this mix of content and behaviour just fine. But should we use it?

If you have only a small website, and you’re only binding to a handful of events, then maintaining things won’t present too much of a problem. That’s the argument for JavaScript in your markup. Now, here are two arguments against using this technique:

  1. It relies on old tricks.
  2. Keeping code in one place - rather than littering content with little bits of it - makes it easier to maintain and update.

Keeping JavaScript out of your markup is especially important if a site is large. Most programmers have better things to do than go looking for code hardwired into the content. And new and returning (perhaps after maternity leave, or an extended caravanning holiday) programmers need to get up-to-speed swiftly, a task made easier if the narrative of the program tells the full story, no pages bits missing. Here’s our JavaScript again, but this time it’s not riding an HTML element:

1
2
3
4
5
6
7
// Take Two - Click event on a button element
window.onload = function() {
    var button2 = document.getElementById("button2");
    button2.onclick = function() {
    alert("This feels better!");
  };
};

Otherwise, not much else has changed: We’re still setting an onclick property to a button.

Of course, things do change - we advance quickly into the future - and we want our sites and applications to keep up. Along the way, things get more sophisticated and demands change, so stay awake! One thing worth knowing about today’s premier event model - the W3C standard event model - is a single event can trigger multiple responses / event handlers, e.g.:

1
2
3
4
5
6
7
8
9
10
11
12
// NB Won't work for older versions of Explorer (pre-IE9)
window.onload = function() {
  var button3 = document.getElementById("button3");
  
  button3.addEventListener("click", function() {
      alert("I'm thinking...");
      }, false);
      
  button3.addEventListener("click", function() {
      alert("I like it!");
      }, false);
};

You can achieve the same double alert without addEventListener, but in this case one response / event handler must do it all, e.g.:

1
2
3
4
5
var button = document.getElementById("button");
button.onclick = function() {
  alert("I'm thinking...");
  alert("I like it!");
};

It follows that addEventListener allows you to bind a handler to an event from multiple places in your web app (without overwriting handlers set elsewhere). A web app will often have multiple JavaScript programs running at the same time; programmers working within a particular program can fearlessly add event handlers without consulting other programs.

An addEventListener function must take three parameters: event type (full list here), event handler, and finally a boolean value (almost always false). Really, really modern browsers don’t require the third parameter - if it’s not passed it’s default is false - but you should include it for the benefit of the masses. I’ll write a post about this final parameter next, since it concerns bubbling - a simple feature with big implications.

IE9 supports addEventListener, but we include the similar method attachEvent for older versions of Explorer (IE5 and later):

1
2
3
4
5
6
7
8
9
10
11
12
window.onload = function() {
  var button4 = document.getElementById("button4");
  var handlerA = function() { alert("I'm groovy!"); };
  var handlerB = function() { alert("I wish I was groovy!"); };
  
  if(button4.addEventListener) {
      button4.addEventListener("click", handlerA, false);    
  } else if(button4.attachEvent) {
      // NB Takes two parameters
      button4.attachEvent("onclick", handlerB);             
  }
};

A quick note about the final example: We’ve declared our handler functions first, passing them by reference. From the code I’ve seen, this seems to be a common practice, to help keep code readable when more is going on.

Function Smackdown: Function Statement vs. Function Expression

| Comments

I’ve recently been reading ‘JavaScript: The Good Parts,’ by Douglas Crockford. This concise book defines a subset of core JavaScript that’s robust and powerful: The Good Parts. Appendix B identifies The Bad Parts, and sets our competitors - the function statement and the function expression - apart.

ROUND ONE - LOOKS (CAN BE DECEIVING)

Function Statement

Our competitors may look alike, but the function statement has two distinguishing characteristics: the declarative keyword function always comes first, and you must name it. Here’s what it looks like:

1
2
// What we see
function funcName(){}

Pull back the curtain, though, and the function statement expands into a variable with a function value:

1
2
// Under the hood
var funcName = function funcName(){}

Function Expression

Absent the mark of the function statement, you have the function expression. The function expression is optionally named (but normally anonymous), e.g.:

1
2
3
4
5
// Stores ref. to anonymous function in a variable 
var funcRef = function(){};

// Stores ref. to named function in a variable 
var funcRef = function funcName(){};

WINNER: Function Expression. Crockford’s manual argues the case for clear code. The function expression is clearly recognisable as what it really is (a variable with a function value).

ROUND TWO - (UNPREDICTABLE) BEHAVIOUR

Function Expression

Variables are subject to a thing called hoisting. Irrespective of their apparent place in the flow of things, their var part is removed and hauled to the top of a containing (whether function or global) scope, and initalised with undefined:

1
2
3
4
5
6
// What we see
var funcRef = function(){};

// Under the hood
var funcRef = undefined;
funcRef = function(){};

Function Statement

The function statement - while just shorthand for a var statement with a function value - is treated differently: the whole lot is hoisted. For this reason, you can call a function statement before you have declared it in your code:

1
2
3
4
5
6
7
8
9
10
console.log(statement()); // I am a function statement.
console.log(expression()); // TypeError...

function statement(){  
  return "I am a function statement.";
}

var expression = function(){
  return "I am a function expression.";
}

WINNER: Function Expression. Hoisting is already a behind-the-scenes behaviour that can cause head scratching. The particular behaviour of the function statement can lead to more furious head scratching.

ROUND THREE - SUPER POWERS

Function Statement

The function statement is widely used and performs just fine, but it has an obvious limitation: You can’t immediately invoke it.

Function Expression

The function expression is more flexible, e.g.:

1
2
3
4
// Executed immediately
(function() {
   alert("I am not a function statement.");
}());

Parentheses are required to nudge function out of statement position (can’t immediately invoke), and into expression position (can immediately invoke). Crockford recommends grouping the entire invocation inside parentheses for clarity - what’s important here is the product of the invoked function - otherwise, Crockford argues, “you’ve got these things hanging outside of it looking like dog balls.”

WINNER: Function Expression.

FINAL SCORE: Function Expression Wins 3 - 0

CONCLUSION - I HEART A GOOD MANUAL

It turns out the function statement came first; the function expression was added to JavaScript later. The result is two very similar ways of defining JavaScript functions. Logically, the addition was intended to improve the language, and, in this case, it would seem this end was achieved.

If you haven’t already seen it, here’s a particularly entertaining speech (2011) Crockford gave on his approach to JavaScript:

Today’s smackdown was inspired by Andrew Torba’s Startup Smackdown: Treehouse vs. Codecademy