Terse JavaScript 101 – Part 2

Posted in ‘JavaScript‘ by James Padolsey on October 29th, 2011

Part one, posted last week, explored a few different ways of de-cluttering your JavaScript, and, in the process, making it more readable.

Some developers don’t like the idea of using a language’s more idiosyncratic features because it does, potentially, make your code less readable in the eyes of those who haven’t learned the language properly. I think it’s still up for debate. While you’re pondering that, part II awaits…

If you haven’t checked out the “Truthy & Falsey” introduction then please do so before continuing.

Looping

It’s something we barely think about but JavaScript’s expressive diversity allows us to invent new patterns for looping. First, there’s the standard:

for (var i = 0; i < array.length; i++) {}

This is conventional and will be known to developers coming from any language. There’s nothing inherently wrong with it. That said, for me, it’s not ideal.

The first improvement I usually make is to cache the length property of the array:

for (var i = 0, l = array.length; i < l; i++) {}

This doesn’t make it shorter, but it does make it more efficient, although marginally so…

Another change we can make is to combine the iteration expression (i++) and the conditional expression (i < l), like so:

for (var i = -1, l = array.length; ++i < l;) {}

Notice that we’re starting with an index of -1, but won’t worry because before the loop’s body runs, the conditional expression is run, and in the above code, the conditional expression is iterating the index and testing it against the length all in one.

It’s important to note that the prefix increment/decrement operators (++i/--i) return the changed value, while the postfix increment/decrement operators (i++/i--) return the old value. To make this clearer:

var x = 5;
alert(x++); // alerts 5 (old value)
alert(x); // alerts 6

var y = 5;
alert(++y); // alerts 6 (new value)
alert(y); // alerts 6

Another looping “pattern” in JavaScript is to assign and rely on what’s returned from that assignment for the conditional expression:

var elements = document.getElementsByTagName('a');

for (var i = -1, el; el = elements[++i];) {
  el; // => a single element
}

Yesterday’s post on truthy & falsey bears some relevance here. The expression el=elements[++i] will return the value of elements[++i]. If this value is falsey the loop will not continue. An element list is full of truthy values (objects). We don’t need to be worried about falsey values. Note that in this approach, you may be sacrificing performance for terseness.

In many situations, we do want to iterate over falsey values too, e.g.

var myArray = [1, 2, 3, null, 8, 54, null, 0, 32];

With something like this it would be best to use the traditional i<length conditional expression, but if you’re so inclined feel free to mix the conditional and iteration expressions together like shown further up (++i<l).

If we were feeling a bit crazy, we could combine everything — iteration, conditional test, and assignment of indexed value — in a single expression:

var array = ['a','b','c'];

for (var i = -1, l = array.length, item; item = array[++i], i < l;) {
  alert(item);
}

// alerts, a, b, c

Here we used the useful comma operator which always returns its right-hand operand. In this example we used it to make sure that i < l is what the condition expression returns. Before the comma we’re assigning the value at the iterated index within the array.

I don’t really suggest doing all of this in one line, and to be honest, there’s nothing wrong with conventional looping structures. What I am trying to put across is how much expressive diversity JavaScript provides.

Assignments

Assignments are expressions too, so you can slot them in wherever you want:

var a = 1;
alert(a = 2); // alerts 2
alert(a); // alerts 2

An assignment operator will always return whatever is on its right-hand side. Be careful with slotting in assignment expressions wherever you want though, because they can be misconstrued for equality operators. For example:

var match;

if (match = '1/2/3'.match(/\d/)) {
  //...
}

To some, upon initial inspection, it may appear that we’re testing match for equality against '1/2/3'.match(/\d/) when in fact the latter is being assigned to the former, and the if statement will run if the assignment expression returns a truthy value (i.e. if its right-hand side operand is truthy).

Casting to a number

Quick and easy:

var str = '222';
var num = Number(str); // => 222

typeof num; // => 'number'

A shortcut is the unary plus (+) operator, used like so:

var str = '222';
var num = +str; // => 222

typeof num; // => 'number'

It works in exactly the same way.

Casting to a string

Once again, quick and easy:

var arr = [1,2,3];
var str = String(arr); // => '1,2,3'

typeof str; // => 'string'

The shortcut, this time, is to simply concatenate an empty string to the value that you’re casting:

var arr = [1,2,3];
var str = '' + arr; // => '1,2,3'

typeof str; // => 'string'

Saving references

Property lookup can be verbose and inefficient. To save space and to benefit performance it’s common to save references and access those properties via the new reference instead of having to evaluate the entire expression every time you want the nested value:

// Original:
document.body.style.color;

// "Caching"
var style = document.body.style;

// Whenever I need to access the `color` value:
style.color;

It’s often referred to as caching. Essentially, all that’s happening is that a new reference is being created for an object and being assigned to an identifier that you specify. Let’s start with this:

var data = {
    config: {
        doSomething: function(item){
            alert(item);
        }
    }
};

for (var i = -1, l = someArray.length; ++i < l;) {
    data.config.doSomething(someArray[i]);
}

It would make sense to minimise the amount of property access that needs to occur within the loop, and thus, potentially, anywhere else in our application that references data.config too:

var config = data.config;

Now the loop can simply reference config instead of data.config:

for (var i = -1, l = someArray.length; ++i < l;) {
    config.doSomething(someArray[i]);
}

We could even “cache” the function itself:

var doSomething = data.config.doSomething;

And then call it directly within the loop:

for (var i = -1, l = someArray.length; ++i < l;) {
    doSomething(someArray[i]);
}

IMPORTANT: It’s important to note that, when you assign a member function (that is, a function that is a property of an object) you are de-binding its this value, i.e. the context in which it runs. Here’s an example:

var obj = {
    value: 234,
    fn: function(){ return this.value; }
};

obj.fn(); // => 234

var fn = obj.fn;
fn(); // => undefined

De-binding the fn method will make its context the global (window) object instead of the obj which we defined, so when our fn function looks for its `this.value` it won’t find it (because this is the window, which doesn’t have `value` defined).

End of part 2

Advertisements

Terse JavaScript 101 – Part 1

Posted in ‘JavaScript‘ by James Padolsey on October 18th, 2011

While some folk will argue that verbose code aids readability, I think almost the opposite, and in this post I’m going to list some basic tips for minimising redundant clutter in your code. JavaScript is a fun language at its core — it’s worth learning the tiny details.

I hope this post is useful to someone. I wrote it not for beginners (although it will be helpful to them), but for all those people writing JavaScript on a daily basis yet haven’t been afforded the time/motivation to get to know the language properly.

new Object()

Nope, don’t do this:

var o = new Object();

Or any of this:

var a = new Array();
var b = new Object();
var c = new RegExp("1(.)3");

Do this instead:

var a = [];
var b = {};
var c = /1(.)3/;

Array literal, object literal, regular expression literal. They rock. There’s usually no need to use the constructor functions when literals are available (please see the note below though).

Note: There are situations when calling Array or RegExp directly can be useful. In such situations, you needn’t bother with the new operator. Array(1,2,3) will produce the same as new Array(1,2,3). Calling RegExp directly can be useful for dynamically building a regular expression from various strings.

Calling a constructor

If you’re not passing any arguments then the parenthesis are not required. E.g.

var a = new Animal();

… and this becomes:

var a = new Animal;

Petty, perhaps. Still worth knowing though.

var;var;var

Quick and easy. Less of this:

var fun = 123;
var tun = 456;
var run = 789;

And more of this:

var fun = 123,
    tun = 456,
    run = 789;

This is why you should use a tab width of FOUR (or 4 spaces).

Undefined & Null

The following is universally true in JavaScript (assuming undefined hasn’t been mutilated):

undefined == null

“So what?”, you say? Well, it means you can replace this:

if (foo === undefined || foo === null) {
    //...
}

… With this:

if (foo == null) {
    //...
}

If something is == to null then it is either null or undefined. Those are the only possible values.

Returning undefined

Not returning something from a function is the same as returning undefined, so you may as well not bother explicitly returning undefined:

function a() {}
function b() { return; }
function c() { return undefined; }

a() === b(); // true
b() === c(); // true

Note: you should be careful with the undefined value as it can be changed. E.g. You can do undefined = true beforehand. The universe would shatter if you did that though, so please don’t. Many libraries declare an empty (undefined) variable in an enclosed scope, which provides a real undefined:

(function(){

    // My private scope. They can't see me in here.

    var undef;

    undef; // => definitely undefined

}());

Or, more succinctly:

(function(undef){

    undef; // => definitely undefined

}()); // <- not passing anything in!

Empty array values

This is entirely legal in JavaScript:

var a = [,,,'foo'];
a[3]; // => "foo"

One potential use-case of this was discussed in my recent post, `match.()` trick.

Less blocks, more expressions

I’m sure we’ve all seen something like this before:

function validateFoo(foo) {
    var regexResult = /^foo+$/.test(foo);
    if (regexResult) {
        return true;
    }
    return false;
}

A cleaner and more sensible solution is this:

function validateFoo(foo) {
    return /^foo+$/.test(foo);
}

No fussing with if statements and multiple returns. You can do everything within a single return statement.

Another example. We want to create a function that logs a name, specified by the arguments forename and surname, but if these arguments aren’t passed then the function should use the default values, “Bob” and “Smith”, respectively:

function printName(forename, surname) {

    if (forename == null || forename == "") {
        forename = 'Bob';
    }

    if (surname == null || surname == "") {
        surname = 'Smith';
    }

    console.log(forename + ' ' + surname);

}

This can be condensed to:

function printName(forename, surname) {

    forename = forename || 'Bob';
    surname = surname || 'Smith';

    console.log(forename + ' ' + surname);

}

Here, we’re using the logical OR operator (||) to provide a default value (right hand side) if the left hand side evaluates to false. Values that evaluate to false (i.e. “falsey”) are: An empty string (""), null, undefined, 0 and false.

So, this:

forename = forename || 'Bob'

… is essentially saying: if forename is a truthy value, then assign forename to forename (in other words: don’t do anything), but if it is a falsey value (e.g. an empty string), then assign the string "Bob" to forename.

So, our new printName function will behave like so:

//                            -- Logged --
printName();                  // Bob Smith
printName(0, 0);              // Bob Smith
printName(false, null);       // Bob Smith
printName('James');           // James Smith
printName('', 'Jones');       // Bob Jones
printName('Bill', 'Jones');   // Bill Jones

Part 1 [OVER]

That’s it for today. There may be a part two soon enough, depending on how useful this is to readers. I know many of you have surpassed this stage of learning, so sorry for boring you.

Recommended viewing/reading

Seriously, if you’re writing JavaScript as part of your job then you definitely owe it to future maintainers of your code to learning JS properly.

EDIT: Crockford links don’t work. The entire video can be seen on youtube instead.