A. Jesse Jiryu Davis

Category: Javascript

Review of "JavaScript: The Good Parts" by Douglas Crockford

A short, dense book with a pretty butterfly on it, describing a subset of Javascript and distinguishing which parts of the language "should" be used and which not. The author is a renowned sage, and he wrote JSLint, a widely-used tool for [ ... ]

Javascript the good
parts

A short, dense book with a pretty butterfly on it, describing a subset of Javascript and distinguishing which parts of the language "should" be used and which not. The author is a renowned sage, and he wrote JSLint, a widely-used tool for enforcing his preferences on your scripts. Those preferences are reflected here.

Some of his opinions seem obsessive and eccentric (it's not OK to write i++?), but others are invaluable. For example, you should make a habit of following the Kernighan & Ritchie style of braces: that is, you should write opening braces ("{") at the end of a line rather than the beginning of the next line, because if you ever write this:

return
{
    a: 1
};

... it will silently return undefined and ignore your actual return value. Such precautions, which defend against dangers the novice hasn't imagined, are born of years of deep Javascript experience. They're this book's primary worth.

The book claims to be for developers new to Javascript, but some basic concepts are not very well explained. For example, the book provides a brief and incomprehensible description of the relationship among Javascript objects, prototypes, and functions, which will not enlighten someone not already familiar with Javascript. It then shows workarounds for implementing a cleaner object model, which is welcome; but if you don't immediately understand the need for the workaround, read a different Javascript book than this one.

A large portion of the book is occupied by flowcharts describing the syntax of the language. For example, half a page is a flowchart describing how to format floating-point numbers:

Floating
point

If I were a finite-state automaton who wanted to know how to recognize floating-point numbers, this would be useful for me. Since I am a human being who can already read and write floating-point numbers, it's an inexplicable waste of space. I'm baffled that the author thought such diagrams served any purpose, and that O'Reilly allowed him to include them and assigned someone to lay them out for publication. If anyone can explain this to me I'd be grateful.

In all, a useful 30-page paper whining to be released from a 200-page book. Worth the read, but skip the flowcharts. Evaluate the author's recommendations for yourself. Use his JSLint tool, but take its output with a grain of salt.

Adding an "include" tag to Underscore.js templates

I use Backbone.js a lot lately, and since Backbone requires Underscore.js, I usually end up using Underscore's templates rather than introducing another Javascript library dependency like Mustache templates. But Underscore's [ ... ]

I use Backbone.js a lot lately, and since Backbone requires Underscore.js, I usually end up using Underscore's templates rather than introducing another Javascript library dependency like Mustache templates. But Underscore's micro-templating language has an omission that bothered me today: templates can't include each other.

So here's a quick and dirty <% include %> tag for Underscore templates:

// Extend underscore's template() to allow inclusions
function template(str, data) {
    // match "<% include template-id %>"
    return _.template(
        str.replace(
            /<%\s*include\s*(.*?)\s*%>/g,
            function(match, templateId) {
                var el = document.getElementById(templateId);
                return el ? el.innerHTML : '';
            }
        ),
        data
    );
}

As you can see, the code simply replaces tags like

<% include foo %>

with the contents of the element with id "foo". Use it by throwing code like this into the body of your HTML page:

<script type="text/template" id="base-template">
    Here is a number: <%= n %>
</script>

<script type="text/template" id="imaginary-template">
    <% include base-template %> + <%= imaginary %>i
</script>

And in your Javascript code, do this:

// Outputs "Here's a number: 17"
function showSimpleNumber() {
    var t = template($('#base-template').html());
    $('body').html(t({ n: 17 }));
}

// Outputs "Here's a number: 17 + 42i"
function showComplexNumber() {
    var t = template($('#imaginary-template').html());
    $('body').html(t({ n: 17, i: 42 }));
}

Enjoy! I leave as an exercise for the reader:

  1. Cache included templates so the template() function needn't keep doing document.getElementById().innerHTML for an often-included template
  2. Create replaceable blocks in templates
  3. Pass variables from one template to another

Using jQTouch.js with iButton.js

jQTouch is a jQuery-based Javascript library that simulates an iPhone-like interface using only Javascript and HTML5. It's designed for WebKit browsers (Safari Desktop, Safari Mobile, Android, Chrome) but is adaptable to Firefox [ ... ]

jQTouch is a jQuery-based Javascript library that simulates an iPhone-like interface using only Javascript and HTML5. It's designed for WebKit browsers (Safari Desktop, Safari Mobile, Android, Chrome) but is adaptable to Firefox with little work. (Don't ask about IE.) By default, it renders HTML like this:

<span class="toggle"><input type="checkbox"></span>

... as toggle switches, like this:

 Another library, iButton.js, provides similar functionality but has some advantages: it works on all browsers, you can easily togglify your checkboxes at runtime, dragging laterally across the control with your mouse or fingertip works as expected, and frankly it makes prettier toggles:

So you might be motivated to combine jQTouch with iButton.js. It should be simple — just remove all the <span class="toggle"> tags and run iButton's initialization method — but you'll run into some troubles. (If you don't believe me when I say "troubles", skim this discussion.)

So, here's the precise problem with combining these two libraries.

When jQTouch initializes, it styles every top-level div with display=none, except for the currently showing div. Here's the CSS rules it uses:

#jqt > * {
  display: none;
}

#jqt > .current {
  display: block !important;
  z-index: 10;
}

This way jQTouch can treat top-level divs like screens (for you iOS devs, that's a UIViewController) in an iOS app, hiding and showing them according to where the user is in the navigation stack.

When iButton.js initializes, it wraps every checkbox with its fancy toggle-control HTML, and then it measures the width of the HTML it created so it knows how far to slide the toggle control when a user clicks on it.

Alas, it's impossible to measure the width of a hidden element. First jQTouch hides all but the current div, then iButton tries to initialize all the toggles, and it thinks they're all zero pixels wide.

My solution is to wait for jQTouch to display a page before I run iButton on the checkboxes in that page, like so:

var pagesWithCheckboxes = _.uniq($('input[type="checkbox"]').closest('div.page'));
_.each(pagesWithCheckboxes, function(page) {
    var $page = $(page);
    $page.bind('pageAnimationEnd', function(e, info) {
        if(info.direction === 'in') {
            $page.find('input[type="checkbox"]').iButton();
        }
    });
});

_.uniq() and _.each() are from underscore.js. I use _uniq() to ensure I don't bind the event handler multiple times to pages with multiple checkboxes.

A final note: if you create checkboxes dynamically after the page has loaded, you must call $(my_new_checkbox_element).iButton() on them, once they're visible, to ensure they get the proper toggle-switch behavior.