Posts tagged "javascript"

The perils of using JavaScript objects as sets

One question I'm fond of asking in interviews is how to create a set of strings to which values may be added in an efficient manner. Furthermore, membership checks must be reliable and as fast as possible. This post can be considered the model answer. ;)

Decorators in JavaScript

A decorator is a function which takes a function and returns a function:

decorator = (fn) -> fn

Obviously, this doesn't do anything useful. It's the fact that a decorator can return a function which behaves similarly to the function passed to it that makes the pattern interesting. Commonly a decorator will simply wrap a function invocation in a check of some sort:

var loginRequired = function (fn) {
  return function () {
    if (!user.authenticated) {
      return window.location.replace('/login');
    }
    fn.apply(null, [].slice.apply(arguments));
  };
};

The above decorator could be used to "guard" actions that only authenticated users are permitted to perform:

var changeUsername = loginRequired(function (username) {
  $.ajax({
    type: 'PUT',
    url: '/api/1.0/users/' + user.id,
    data: {username: username}
  })});

var changePassword = loginRequired(function (password) {
  $.ajax({
    type: 'PUT',
    url: '/api/1.0/users/' + user.id,
    data: {password: password}
  })});

var deleteAccount = loginRequired(function () {
  $.ajax({
    type: 'DELETE',
    url: '/api/1.0/users/' + user.id
  })});

The CoffeeScript equivalent is quite a bit clearer:

changeUsername = loginRequired (username) ->
  $.ajax
    type: 'PUT'
    url: "/api/1.0/users/#{user.id}"
    data: {username}

changePassword = loginRequired (password) ->
  $.ajax
    type: 'PUT'
    url: "/api/1.0/users/#{user.id}"
    data: {password}

deleteAccount = loginRequired ->
  $.ajax
    type: 'DELETE'
    url: "/api/1.0/users/#{user.id}"

Decorators are commonly used in Python — which provides special syntax for "decorating" functions — but are rarely seen in JavaScript code. This despite the fact that JavaScript's first-class functions are ideally suited to the task. Perhaps CoffeeScript's lighter-weight function syntax will result in decorators making more frequent appearances in JavaScript code.

Escaping HTML in JavaScript

I recently came across an interesting article at wonko.com on HTML escaping, which provoked me to rewrite Bitbucket's escape function (invoked from within Underscore templates):

function makeSafe(text) {
  return text.replace(/[&<>"'`]/g, function (chr) {
    return '&#' + chr.charCodeAt(0) + ';';
  });
};

This ensures that inserted content cannot escape the confines of a quoted attribute value. Unquoted attributes are more problematic:

Unquoted attribute values are one of the single biggest XSS vectors there is. If you don’t quote your attribute values, you’re essentially leaving the door wide open for naughty people to inject naughty things into your HTML. Very few escaper implementations cover all the edge cases necessary to prevent unquoted attribute values from becoming XSS vectors.

To accommodate unquoted attribute values, the following function could be used instead:

function makeSafe(text) {
  return text.replace(/\W/g, function (chr) {
    return '&#' + chr.charCodeAt(0) + ';';
  });
};

I created a jsPerf test case which confirms that there's a performance hit associated with using this more liberal regular expression. Keep in mind, though, that if “A” takes 1ms to execute and “B” takes ten times as long, “B” still only takes 10ms. Quite often a significant comparative speed difference is insignificant in absolute terms; I'd argue that this is the case here.

Getting truth out of the DOM – Yehuda Katz

Recording of Yehuda Katz's presentation from Bay Area jQuery Conf 2011.

While watching this it finally became clear to me why storing state in the DOM is a terrible idea for complex applications. The approach comes unstuck as soon as one wishes to display an entity more than once in a view (such as in a list–details split view).

End of string anchor in JavaScript regular expressions

JavaScript's regular expressions are less than awesome, sadly. One limitation is the lack of start of string and end of string anchors. In Perl, for example, \A matches the start of a string, \Z the end.

Most of the time it's possible to get by with ^ and $ which act like \A and \Z except in multiline mode where they match the start and end of any line.

It's possible, though, to have a lookahead act as an end of string anchor in multiline mode:

> /bar(?![\s\S])/m.test('foo\nbar')
true
> /bar(?![\s\S])/m.test('foo\nbar\n')
false
> /bar(?![\s\S])/m.test('foo\nbar\nbaz')
false

(?![\s\S]) at the end of the pattern is equivalent to \Z.

Start of string anchor?

Unfortunately, since JavaScript offers lookahead but not lookbehind, this approach can't be used to simulate \A.

Repeating strings in JavaScript

Python and Ruby share beautiful syntax for repeating strings; PHP's syntax is characteristically ugly.

Python

'=' * 5

Ruby

'=' * 5

PHP

str_repeat('=', 5)

JavaScript?

True to form, repeating strings in JavaScript is ugly and counterintuitive, but kinda cool.

new Array(5 + 1).join('=')

Bitwise NOT operator proves useful in JavaScript

JavaScript is a wonderful language. Its syntax, though, leaves a lot to be desired at times. String pattern matching, for example, is rather ugly.

// ugly option 1
if (text.indexOf('✈') != -1)

// ugly option 2
if (text.indexOf('✈') >= 0)

// ugly option 3
if (text.indexOf('✈') > -1)

It'd be nice to be able to write text.contains('✈'), which is both intuitive and self-documenting. The language does provide a way to make such expressions terser, but it's far from obvious.

// bitwise NOT
if (~text.indexOf('✈'))

Bitwise operators make my head spin, but the Perl programmer in me thinks they're awesome. I don't profess to understand why exactly the bitwise NOT operator does what it does, but I've played with it enough to know how it behaves. It's equivalent to the following function, at least for the values that can be returned by indexOf.

function bitwiseNot(n) {
    return -n - 1;
}

indexOf returns -1, 0, 1, 2, 3, or some other positive integer. When these values are used as operands for the bitwise NOT operator, the results are 0, -1, -2, -3, -4, and so on. Therefore, ~text.indexOf('✈') is equivalent to text.contains('✈') in Boolean contexts.

JavaScript date and time localization

This post has been a long time coming.

Reminder message
Reminder message, dated 18 January 2010

It's unacceptable for any website or web application to output dates and times using an arbitrary time zone. Displaying dates and times in UTC/GMT is only slightly better: dates cannot be relied upon, and users must perform mental gymnastics in order to localize date–time combos.

Converting integers to ordinals

When dealing with dates, it's not uncommon to need to convert an integer into an ordinal number (1st, 2nd, 3rd, etc.). While making improvements to Mango recently I wrote a function to do this, first in Python, later in JavaScript.

Python

def ordinal(n):
    if 10 < n < 14: return u'%sth' % n
    if n % 10 == 1: return u'%sst' % n
    if n % 10 == 2: return u'%snd' % n
    if n % 10 == 3: return u'%srd' % n
    return u'%sth' % n

JavaScript

function ordinal(n) {
    if (10 < n && n < 14) return n + 'th';
    switch (n % 10) {
        case 1: return n + 'st';
        case 2: return n + 'nd';
        case 3: return n + 'rd';
        default: return n + 'th';
    }
}

By special-casing 11, 12, and 13, the function becomes incredibly simple.

I'm pleased to have found a context in which JavaScript's switch statement is almost elegant. The problem, usually, is the need to break to prevent fall-through. When used within a function, though, the return statement is able to perform this role, making the JavaScript code almost as readable as the Python equivalent.

Filtering lists in Python, Ruby, and JavaScript

Recently I listened to Gary Bernhardt comparing Python and Ruby. In the talk Gary states that he finds Ruby code ugly and Python code beautiful. He then goes on to say that the things which reduce Ruby's aesthetic appeal are the very things which allow Ruby to do beautiful things impossible in Python.

Gary provides several examples of equivalent code in Python and Ruby to highlight situations in which one language reads better than the other, such as the following.

Python:

'\n'.join(obj.name
    for obj in (
        repository.retrieve(id)
        for id in ids)
    if obj)

Ruby:

ids.map do |id|
  repository.retrieve(id)
end.compact.map do |obj|
  obj.name
end.join('\n')

The Ruby code (the one beginning with ids.map) reads top to bottom and is easy to follow. The Python code is equally succinct but takes a bit of effort to decipher.

I've been greatly enjoying the act of writing JavaScript lately, so simply for pleasure I worked out the JavaScript equivalent.

My first attempt used the filter array method.

ids.filter(function (id) {
    var obj = repository.retrieve(id);
    return obj && obj.name;
}).join('\n');

filter, though, just removes from an array the items which fail the provided "test". So the code above is on the right track, but fails to produce a list of names.

reduce is the correct method for the job. reduce "reduces" an array to a single value, which could be a string, an object, another array — whatever!

Note the empty array ([]) on line 5 – that's our "accumulator".

ids.reduce(function (ids, id) {
    var obj = repository.retrieve(id);
    if (obj && obj.name) ids.push(obj.name);
    return ids;
}, []).join('\n');

Not bad. It's not as elegant as the Ruby code, but it's not "inside out" the way the Python code is.

Efficient rounding in JavaScript

So you have some number, x, which you want to round to the nearest integer. Easy, right?

x = Math.round(x);

Sure, but is this the fastest option? I think not.

x = x < 0 ? x - 0.5 >> 0 : x + 0.5 >> 0;

What the heck's going on here? >> is JavaScript's right shift operator. It shifts a number's binary representation n bits to the right, where n is the value to the right of the operator. Since n is 0 in this case, no shifting will occur, although the resulting value will be an integer.

Note that this approach results in -82.5 being rounded to -83.

If, for some reason, your code calls Math.round() millions of times, it may be worth investigating the bitwise approach to avoid the overhead of all those function calls.

Stick to Math.round() the rest of the time, though, as it makes for much clearer code. Never optimize prematurely.

Self-caching functions in JavaScript and Python

Earlier I wrote some code which repeatedly calls a function which performs a database query – often the same query. This encouraged me to explore various ways to cache the results of function calls in both Python (to solve my immediate problem) and JavaScript (because I find that language endlessly fascinating).

I played around with Fibonacci, which is a well suited to the task: it can be described in just a couple of lines of code yet benefits enormously from caching due to its recursive nature.

JavaScript Fibonacci without caching

function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 2) + fibonacci(n - 1);
}

Python loops can have else clause?!

I write a lot of Python. I also write a lot of JavaScript. As I switch between the two (often several times in a day) I sometimes find myself trying to do something in one using the syntax of the other. The most common example is joining a list.

Python:

' '.join(['foo', 'bar'])

JavaScript:

['foo', 'bar'].join(' ')

Often — as is the case above — the syntactical differences are minor, but there are times when there's no direct translation.

MooTools, for example, adds the every method to the Array object. This makes it possible to write some rather terse conditional statements.

var numbers = [87, 33, 21, 75];
if (numbers.every(function (n) { return n % 3 == 0; })) {
    window.alert('The numbers are all divisible by 3.');
}

Python lists have no comparable method, so how would one write this in Python?

numbers = [87, 33, 21, 75]
if [n for n in numbers if n % 3 == 0] == numbers:
    print 'The numbers are all divisible by 3.'

This approach involves using a list comprehension to create a list of numbers which are divisible by 3, and comparing this list to numbers. If the lists are equal, everything in numbers is divisible by 3.

Update —

As Rafael Almeida pointed out on Twitter, there is an elegant way to express this in Python:

if all((n % 3 == 0 for n in numbers)):
    print 'The numbers are all divisible by 3.'

Now for something a bit more challenging

Assume that we have a list of documents, and we want to know which of the documents contain all the terms in a list of search terms.

// (MooTools) JavaScript

var terms = ['python', 'list', 'methods'], matches = [];
documents.each(function (document) {
    if (terms.every(function (term) {
        return document.body.indexOf(term) != -1;
    })) matches.append(document);
});

Here, we could use the list comprehension approach as before.

# Python

terms = ['python', 'list', 'methods']
matches = []
for document in documents:
    if [t for t in terms if document.body.find(t) != -1] == terms:
        matches.append(document)

This is reasonably succinct, but not terribly efficient since each document is checked for every search term. Given that we're not interested in documents that lack even a single search term, it should be possible to rewrite this code so that we don't waste time on lost causes.

It turns out that Python has just the thing for the job: in Python, a loop statements may have an else clause!

terms = ['python', 'list', 'methods']
matches = []
for document in documents:
    for term in terms:
        if document.body.find(term) == -1:
            break
    else: # every term was found
        matches.append(document)

From 4. More Control Flow Tools:

Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement.

I'm looking forward to finding more good spots to make use of else clauses with my Python loops. :D

JavaScript, JavaScript, everywhere

Over the past few months I've reached a startling realization: JavaScript is a tremendously capable language.

The reason that it took me so long to discover this is that the playing field has never been fair. On the one hand I've been writing application code for the server, a stable, predictable environment. On the other hand I've been adding interactivity on the client's side, dealing with inconsistencies on multiple fronts, not least of which is the DOM API.

Comparing Python and JavaScript, for example, by using the former to quickly put together a website using the excellent Django framework while using the latter to add drag and drop functionality is to compare apples and oranges. Actually, it's more like comparing apples to root canals.

Positioning elements using MooTools

I've spent the afternoon creating a custom scrollbar for a products viewer which utilizes CSS transitions, reflections, and other goodness.

Simple arithmetic dictates how long to make the scrollbar and where to position it, but I could not get my theoretical calculations to play out in the browser.

It turns out that I'd been calling the wrong MooTools method. I'd been doing…

element.setStyle('left', offset);

rather than…

element.setPosition({ x: offset });

Frustratingly, setStyle('left', offset) appeared to work, but its behaviour was unpredictable. I'm still confused by this, but at least I'm no longer stuck.

setTimeout fix for -webkit-transition

Here's a simple animation which utilizes webkitTransition:

Click to animate

The code behind this example is not complicated:

element.style.webkitTransitionProperty = 'left';
element.style.webkitTransitionDuration = '2s';
element.addEventListener('click', function () {
    this.style.left = '100px';
    this.addEventListener('webkitTransitionEnd', function () {
        this.style.left = 0;
    });
});

wmd ftw!

Comment forms that don't provide previews — or at least an indication of how comments are processed — really annoy me. If I decide to leave a comment I take care to avoid spelling mistakes and grammatical errors. It's quite upsetting, then, to see my code snippet completely mangled and my carefully typed links displayed in plain text (<a href="…).

Despite my appreciation of the preview, not one of my sites provided this service until a few hours ago. Now that I've migrated from WordPress to Mango I'm able to spend some time working on front-end code. My first two challenges were localizing dates and times, and integrating wmd.

Getting wmd working turned out to be extremely easy, but I was not content with a live preview of the comment only. No, I wanted the preview to resemble as closely as possible the published result, which meant updating the preview area in response to changes to "name", "e-mail", and "website" as well as to changes to the comment itself.

This was a great deal of fun to implement!

Auto-populating input fields with MooTools

Early this year I wrote a post titled Auto-populating input fields with Prototype. Looking at the code now, I realize that it's not very pretty. I'm rewriting this site's JavaScript in MooTools, and the new code is quite a bit more elegant.

// provide input hints
window.addEvent('domready', function () {
    $$('input[placeholder]').addEvents({
        focus: function () {
            if (this.hasClass('placeholder')) {
                this.removeClass('placeholder').set('value', '');
            }
        },
        blur: function () {
            if (this.get('value') === '') {
                this.addClass('placeholder').set('value', this.get('placeholder'));
            }
        }
    }).fireEvent('blur');
});

I really appreciate the fact that MooTools provides addEvents in addition to addEvent. As a result, the code above is clearer than a well-written Prototype equivalent.

Linkify tweets with regex

Regular expressions are powerful, useful, and — in my opinion — lots of fun! Thanks to the prevalence of Twitter, every web developer will be exposed to regex sooner or later: before outputting tweets in HTML, Twitter names and hyperlinks must be wrapped in anchor tags.

Matching @names

Here's the gist: a match will begin with "@" and the at sign must be followed by one or more word (letter / number / underscore) characters. The @name must either appear at the beginning of the tweet or be preceded by a space. This prevents the regular expression from matching "@example" in "me@example.com".

Extra comma considered harmful

On , David Chambers wrote:

Hi Douglas,

[…] Moments ago I used JSLint for the first time; I plan to use it frequently from this point forward. I have one question, though, concerning the acceptability of extra commas. Consider the following code snippet:

var ninja = {
    name: 'Hattori Hanzou Masashige',
    shuriken: 5,
    attack: function () {
        if (ninja.shuriken) {
            ninja.shuriken -= 1;
            window.alert('Hai-Ya!');
        }
    },
};

JSLint returns an extra comma error for the unnecessary comma preceding the closing brace. I would argue, though, that this in not an error. As far as I'm aware, this comma will not cause problems.

In fact, quite the opposite is true. If one were to insert an additional property or method after attack one would not need to remember to first add a comma. In Django it's considered best practice to include a comma after every item (including the last) in a one item per line collection for this very reason.

I thought I'd give you my two cents, anyway. :)

Regards,

David Chambers

On , Douglas Crockford wrote:

Your awareness is incorrect. Have you tested on IE6?

Forcing browsers to rerender elements

Generally speaking browsers rerender elements as required – in response to DOM changes effected via JavaScript, for instance. There are times, though, when the browser (Internet Explorer, I'm looking at you!) needs a gentle nudge.

Forcing a UI redraw from JavaScript highlights the solution employed by Thomas Fuchs, creator of the popular JavaScript library script.aculo.us:

Element.addMethods({
    redraw: function (element) {
        element = $(element);
        var n = document.createTextNode(' ');
        element.appendChild(n);
        (function () { n.parentNode.removeChild(n); }).defer();
        return element;
    }
});

The post's first comment includes an alternative approach:

element.className = element.className;

I gather that there are situations in which this simple solution fails — it's no silver bullet — but it fixed a problem I encountered in IE8 earlier this evening so I'm pleased to have discovered it!

MooTools every method

A reasonably common task is to determine whether a particular statement evaluates as true for every item in a collection. Take list, for example, an Array containing several numbers:

var list = [4, -1, 3, 2, 5];

One might wish to determine whether all the numbers in list are positive. The required logic is as follows:

  1. assume that all the numbers in list are positive, then…
  2. loop through list until the assumption is proven to be false, or until all items in list have been tested

In plain JavaScript, this can be achieved using a for loop…

var allPositive = true;
for (var i = 0; i < list.length; i++) {
    if (list[i] <= 0) {
        allPositive = false;
        break;
    }
}

… or a while loop (which is slightly more efficient).

var allPositive = true, i = list.length;
while (i--) {
    if (list[i] <= 0) {
        allPositive = false;
        break;
    }
}

Seriously, though, who is writing vanilla JavaScript in 2010? Everyone and their grandmothers are using JavaScript frameworks these days, and there are plenty of good ones out there. I recently made the switch to MooTools from Prototype, after deciding that while jQuery is fantastic, the MooTools philosophy is more to my liking.

With MooTools, one might consider using the Array object's each method instead of a for or while loop.

var allPositive = true;
list.each(function (item) {
    if (item <= 0) {
        allPositive = false;
    }
});

While this gets the job done, it's suboptimal for two reasons: the positiveness of every item is evaluated, which will often not be necessary; and, well, it ain't pretty. ;)

Enter every

As is so often the case in programming, if something seems fiddly and difficult there's probably a better tool for the job. In this case the Array object's every method is the perfect tool for the job.

var allPositive = list.every(function (item) {
    return item > 0;
});

This is terser than is possible with vanilla JavaScript. It reads better too, in my opinion!

Resize browser window to match iPhone viewport dimensions

I've recently become interested in optimizing sites for the iPhone and iPod touch. While nothing beats testing on the device itself, I often find it quicker to test changes on my Mac. Changing the user agent string is a piece of cake in Safari (Develop > User Agent > Mobile Safari) but what about adjusting the browser window's dimensions to match those of the iPhone?

I've created two bookmarklets to allow the current page to be loaded in an iPhone-sized window with a single click:

  • Portrait (labelled "⁑")

    javascript:open(location,'iPhone:portrait','innerWidth='+(320+15)+',innerHeight='+(480+15)+',scrollbars=yes');
    
  • Landscape (labelled "**")

    javascript:open(location,'iPhone:landscape','innerWidth='+(480+15)+',innerHeight='+(320+15)+',scrollbars=yes');
    
iPhone testing bookmarklets
iPhone testing bookmarklets: portrait and landscape

Duplicating arrays in JavaScript

Many of those who write JavaScript do not come from programming backgrounds (while I've written plenty of PHP, Python, and JavaScript, I don't have much experience with "real" programming languages*). As a result, a significant portion of JavaScript coders do not think of variables as pointers to memory addresses. This leads to confusion in cases such as this:

var fruits = ['orange', 'lime'];
var colours = fruits; // naïve attempt to duplicate array
colours.push('yellow');

One might be surprised to learn that fruits now contains not just "orange" and "lime" but also "yellow". Oops! Here's how it went wrong:

var fruits = ['orange', 'lime'];
// fruits points to array containing "orange" and "lime"

var colours = fruits;
// colours now points to that same array!

How, then, does one create a copy of the original array? Slice!

var colours = fruits.slice();

Prototype and script.aculo.us, combined and compressed

Nothing new here. I've combined Prototype 1.6.1 and the various files that make up script.aculo.us 1.8.3 (except unittest.js) into one file, which I've minified using the YUI Compressor. Further compression has been achieved by gzipping the minified file. All three versions are available for download:

I suggest including the Prototype and script.aculo.us version numbers in the src:

<script src="/scripts/prototype+scriptaculous.min.js?p=1.6.1&amp;s=1.8.3"></script>

This prevents caching issues that might otherwise arise upon updating to a newer version of prototype+scriptaculous (I'll update the three files — and this post — each time a new version of Prototype is released).

CSS fixed-position headers

I began this post three months ago, got stuck, and put it in the too hard basket. I wanted to devise a workable solution to my stumbling block before publishing this information. I'm getting ahead of myself, though. First, the background.

As I began writing this post, I had just completed a redesign of this site. The new design removed unnecessary distractions to allow readers to focus on the clearly presented content. I moved site navigation from the sidebar (which I axed altogether) to the header. I decided to fix the header in place so that the navigation and search form would always be visible. This required very little effort, but overcoming the problem posed by fixed-position headers took a great deal of trial and error. To save others from going through this tortuous process I'll describe my various approaches, and list the benefits and drawbacks of each.

Prototype image slider

In my post titled Captions over images I advocate the use of definition lists for captioning images. Earlier today I was asked whether this meaningful markup could be used in conjunction with an "image slider" such as Easy Slider 1.5.

I had a look at the Easy Slider source code and decided to write my own image slider using Prototype rather than hacking someone else's code to pieces. It's a proof of concept rather than a full-blown "plugin", but it demonstrates that such functionality is achievable using elegant, meaningful markup.

Check out the Prototype image slider demo to see the code in action.

Captions over images

This is my response to Chris Coyier's screencast titled jQuery Part 3 – Image Title Plugin which I watched a couple of days ago. Something didn't sit right with me at the time, and I've now worked out what it was: JavaScript is not required!

I'll present a JavaScript-free approach for displaying captions over images that uses truly meaningful markup.

Coda theme for SyntaxHighlighter

It's no secret – I love Coda! It's a pleasure to use. It looks so damn good. When I started using SyntaxHighlighter I set out to create a Coda theme. Thankfully, the good folks at Panic had done the ground work for me. All I had to do was create a style sheet that would make my code snippets look as sexy online as they do in my text editor.

Or so I thought.

Photoshop "save for web" JavaScript

This is a JavaScript function for Photoshop which saves the active document as a 24-bit PNG file. It is equivalent to manually selecting File > Save for Web & Devices… which means that the file size of the resulting PNG will be smaller than would be the case using PNGSaveOptions().

function saveForWebPNG(outputFolderStr, filename)
{
    var opts, file;
    opts = new ExportOptionsSaveForWeb();
    opts.format = SaveDocumentType.PNG;
    opts.PNG8 = false;
    opts.quality = 100;
    if (filename.length > 27) {
        file = new File(outputFolderStr + "/temp.png");
        activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
        file.rename(filename + ".png");
    }
    else {
        file = new File(outputFolderStr + "/" + filename + ".png");
        activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
    }
}

Photoshop on Mac limits the length of a File object's file name to 31 characters. Credit for the rename workaround should go to Mark Walsh who posted the solution on the Adobe forums in a thread titled Save for web filename problems.

Associative arrays in JavaScript

JavaScript does not have associative arrays. (This will be old news to many.)

Confusion arises from the fact that array syntax in JavaScript is very similar to array syntax in PHP, a language that does have associative arrays. Additionally, any object in JavaScript can be treated as an associative array. This means that if one creates a JavaScript Array object and proceeds to use PHP's associative array syntax in an attempt to add items to it, one will succeed in assigning it attribute–value pairs. The object in question need not be an Array for this to work, though, so for the sake of clarity using a vanilla Object is advisable.

To gain a more detailed understanding of why JavaScript appears to have associative arrays, read JavaScript "Associative Arrays" Considered Harmful.

Prototype loader for SyntaxHighlighter

SyntaxHighlighter is a fully functional self-contained code syntax highlighter developed in JavaScript (as stated on its wiki). One of its deficiencies is that it retrieves all its brushes each time a page is loaded, despite the fact that in many cases only one or two (or none) are required.

Currently, Prototype is my JavaScript framework of choice (although I'm really looking forward to trying jQuery). I have used Prototype to create a brush loader for SyntaxHighlighter, which retrieves brushes on demand to reduce page loading times (in certain circumstances).

PHP brush for SyntaxHighlighter

Alex Gorbatchev's SyntaxHighlighter is a well-written bundle which enables syntax highlighting of code via JavaScript. More than twenty languages are supported "out of the box", and brushes (JavaScript files containing language-specific regular expressions) can be created to support additional languages.

Unfortunately, however, several of the brushes that come bundled with SyntaxHighlighter are far from perfect. Have a look at the bundled PHP brush in action below.

Screenshot of PHP code highlighted by SyntaxHighlighter's PHP brush
Screenshot of bundled PHP brush in action

AppleScript syntax highlighting

I've been using Alex Gorbatchev's SyntaxHighlighter to syntactically display code of various languages for several months now. When I decided to post an AppleScript snippet, however, I realised that I was out of luck. SyntaxHighlighter does not include an AppleScript "brush", and a quick flick through the SyntaxHighlighter forums did not bring me any joy.

How hard could it be to write a brush for AppleScript?, I wondered. The handy guide to developing a custom brush got me started, and I was soon busy trying to encapsulate AppleScript's syntax — along with its keywords and countless words and phrases with special meanings — into a handful of regular expressions.