Wednesday 23 May 2012

ECMAScript

ECMAScript

From time to time I find some JavaScript code that is not completely correct. “Not completely” in the sense that you can tell what the program is intended to do and you can see that it's doing it right, but only under certain conditions, having the programmer left the door open for malfunction to happen.

The main reason – if not the only – of such mistakes is the fact that the programmer has written the code thinking in another language, namely Java. The unfortunate choice of name for JavaScript has led many to the erroneous belief that the two languages are closely related and, as a consequence, Java programmers have been “automatically” considered JavaScript programmers. This misconception won recruiters first and it spread so successfully that soon Java developers started to believe it themselves. Then many Java developers got frustrated with their poor performance in JavaScript (so many things just didn’t work the way they expected) and the line “I hate JavaScript” became a commonplace among us.

This is only half the story. The other half, the good one, is that JavaScript is a dialect of ECMAScript, a full-fledged scripting language with some powerful features, like prototypes and weak typing, not to be found in Java, and some others common to both languages but different in syntax and/or semantics. We must accept this: ECMAScritps is a different language; and where do we turn to when we face a different language? Its specification!

A quick look at the spec index should suffice to convince you that we’re dealing with something original and separate from other languages. There are many features that demonstrate this originality, but in this post I’m going to focus on the equality operator (==), the most popular false friend to Java programmers.


== vs ===

ECMAScript defines two equality operators. The Strict Equals Operator (===) works much as the Java ==. The non-strict operator (==), on the contrary, performs some basic transformation on operands of different types before evaluating the comparison, so it may yield surprising results if you’re not familiar with those transformations.

The full description of this operator can be found in chapter 11.9.3 of the spec, The Abstract Equality Comparison Algorithm, but the interesting points can be summarized as follows:
  • undefined == null yields true.
var a;
var b = null;
console.log('type of a: ' + typeof(a));
console.log('type of b: ' + typeof(b));
console.log('a == b >>> ' + (a == b));

/*
Output:
type of a: undefined
type of b: object
a == b >>> true
*/
  • If one operand is a number and the other one is a string, the string is coerced into a number before comparison is made.
var a = "2";
var b = "3";
var c = 3;
console.log('type of a: ' + typeof(a));
console.log('type of b: ' + typeof(b));
console.log('type of c: ' + typeof(c));
console.log('a == c >>> ' + (a == c));
console.log('b == c >>> ' + (b == c));


Output:
type of a: string
type of b: string
type of c: number
a == c >>> false
b == c >>> true

  • If one operand is a Boolean and the other is not, the Boolean is converted to number before == is applied.
var a = "1";
var b = "3";
var c = false;
var d = true;
console.log('type of a: ' + typeof(a));
console.log('type of b: ' + typeof(b));
console.log('type of c: ' + typeof(c));
console.log('type of d: ' + typeof(d));
console.log('a == c >>> ' + (a == c));
console.log('b == c >>> ' + (b == c));
console.log('a == d >>> ' + (a == d));
console.log('b == d >>> ' + (b == d));


Output:
type of a: string
type of b: string
type of c: boolean
type of d: boolean
a == c >>> false
b == c >>> false
a == d >>> true
b == d >>> false

  • If one operand is an object and the other one is a string or a number, the object is converted to primitive and then the comparison takes place. The conversion object-to-primitive is object-dependent and it relies on one of the methods toString() and valueOf(); the details are explained here, but my advice is don’t evaluate objectA == aString nor objectA == aNumber.

The if statement

if (expression) statement
This is closely related to the equality operator, but there’s something more. expression can be anything and it will be evaluated to a Boolean according to the rules that you can find in the specification, chapters 12.5 The if Statement and 9.2 ToBoolean.
It is very common to write code like
if(document.getElementById(“foo”)) {...}
to check whether a DOM element exists in an HTML document. This is fine because we know that getElementById() will return either an object or null. In the first case the expression evaluates to true and in the other case to false.
But we need to be very careful with the if statement if we’re applying it to objects other than HTML documents. The results can be surprizing:

var a =
{
    prop1: 0,
    prop2: "0",
    prop3: {k: 0}
};
console.log('type of a: ' + typeof(a));
if (a.prop1) {
    console.log('a.prop1 evaluates to true')
} else {
    console.log('a.prop1 evaluates to false')
}
if (a.prop2) {
    console.log('a.prop2 evaluates to true')
} else {
    console.log('a.prop2 evaluates to false')
}
if (a.prop3) {
    console.log('a.prop3 evaluates to true')
} else {
    console.log('a.prop3 evaluates to false')
}

Output:
type of a: object
a.prop1 evaluates to false
a.prop2 evaluates to true
a.prop3 evaluates to true

The bottom line

Traditionally JavaScript has been used almost exclusively for scripting web pages so some of its particularities (like the two discussed above) have been under control thanks to the nature of the objects it manipulates (the DOM). But today it is becoming more and more a general-purpose scripting language driven by
  • the development of powerful JavaScript APIs (YUI, JQuery) that exploit the full potential of the language.
  • The advent of Rhino, a Java implementation of ECMAScript that has pushed the language into the server side.
Now it is essential to be aware of the language peculiarities – refer always to its specification – especially when coding server-side JavaScript, when it is just too easy to think that JavaScript is kind of Java.

The blank verse

Now chaps, this section has nothing to do with the subject of this post. I will drop here anything coming to my mind that I want to share. Sometimes it will be something completely off the wall, but not today.

In this first post I want to recommend a reading: Vargas Llosa’s The Dream of the Celt.
Vargas Llosa won 2010 Nobel Prize of Literature and, at the same time, he published this novel. This happened just a few weeks after my coming to Ireland and it was a nice coincidence that one of my favourite writers delivered a book with such sharp Irish tones among so many colours.
A less concise, more factual review can be found here. Enjoy.

No comments:

Post a Comment