Bug Fixes in JavaScript 2

As the the ECMAScript 4 (JavaScript 2) specification comes closer to its final form, a number of aspects have, already, congealed and able to be disseminated and learned. Specifically, the bug fixes to ECMAScript 3 that are being included in ECMAScript 4 are quite refined at this point.

The bug fixes to JavaScript came from a number of places. Generally, however, they have come about due to aspects being under-specified, causing confusion to occur amongst language implementors.

Additionally, bug fixes have come about from universal conventions that have been adopted by implementors causing them to be ported back into the specification.

A full list of the bug fixes can be found on the ECMAScript 4 wiki.

You’ll, generally, find that a number of these fixes are already included in some browser implementations (generally more-so in Spidermonkey-based ones, than others). However, a couple of these are implemented in no browser, at this point (like this propagation) and still others are implemented in all browsers (like single character substrings).

More than anything else, however, these changes represent an attempt to bring greater levels of common-use compatibility to the language (allowing more web pages to work) and bringing backwards compatibility inline with ECMAScript 3 implementations, rather than with the specification.

Generally, you should use this as a guide of what’s to come, not as of what you can universally use, right now.

arguments is now a ‘real array’

arguments is now a ‘real array’, as opposed to an array-like object, with the following distinctions:

  • arguments.toString() behaves like an object’s .toString(), rather than an array’s.
  • If you manipulate the .length property its contents aren’t deleted (if the length is reduced), nor are new items added (if the length is increased).

This means that you can now do simple things like:

arguments.slice(1);

Whereas, previously, you would have to do:

Array.prototype.slice.call( arguments, 1 );

typeof /regexp/ == 'object'

This change makes it such that callable objects return a typeof of ‘object’ rather than of ‘function’.

The result of this fix is best exhibited by an uncommon feature in Spidermonkey that’s caused a lot of confusion. Many don’t know this, but you can do this with a regular expression (in Firefox, et. al.):

/test/('test')
// is equivalent to:
/test/.exec('test')

In this case, a regular expression is an object that is also callable (thus the typeof was actually ‘function’ rather than ‘object’). So while fixing typeof of a RegExp, in Spidermonkey, isn’t a true ECMScript 4 bug fix, it’s indicative of the larger problem being solved. In reality, most users expect the typeof value to be ‘object’ in this case. The adjustment is that callable non-functions now have a typeof of ‘object’, allowing this to behave as one would expect:

typeof /regexp/ == 'object'

this propagation

If you now define a function inside another, its this is bound to the this of the outer function, as opposed to the global object (e.g. window).

This makes the following code possible:

function User(name){
  this.name = name;

  function test(){
    alert(this.name);
  }
  
  test();
}

Whereas, previously, you would’ve had to have used a closure to store a reference to this and retrieve it within test(). The resulting code would have looked something like this:

function User(name){
   var self = this;
   this.name = name;

   function test(){
     alert(self.name);
   }

   test();
} 

undefined, NaN and Infinity

undefined, NaN and Infinity are now immutable global properties. Some implementations already took some of these into account, but now it’s being standardized.

Thus you can do:

1/0 == Infinity
1/'foo' == NaN

RegExp Reconstruction

/regexp/ creates a new, unique, object every time it’s evaluated. For example, the following evaluated to true, previously, even though it shouldn’t have:

var test = [];
for ( var i = 0; i < 2; i++ )
	test.push( /test/ );
test[0] == test[1]
>> true

This now brings RegExp literals in line with all other literals (as to how they are evaluated). This bug led a number of people astray – and in the end it was the third most duplicated JavaScript bugs.

Trailing Commas

When initialising an object, trailing commas are ignored (some implementations already support this).

var obj = {
	a: 1,
	b: 2,
};

It’s now being made expressly clear that a trailing comma in an array initialisation does not create an extra undefined entry at the end of the array. JScript currently gets this implementation detail wrong, even though it was specified in ECMAScript 3. The correct result is as follows:

[a, b,].length
>> 2 (not 3)

Single-Character Substrings

You can now get single characters out of a string by using [index], instead of the .charAt(index) method. This way was already widely implemented.

'string'[0]
>> 's'

Undefined Looping

You can now do a for .. in loop against an undefined object (or a null) without an exception being thrown. For example:

for ( var i in null ) {}
for ( var i in undefined ) {}

This was, originally, intended to throw an error in ECMAScript 3 but this has been reverted due to web pages coming to expect this to work.

Comparison Order

When performing a comparison of two items the order in which they were compared was not guaranteed. It is now specified that the values be retrieved in left-to-right order.

For example, this is what could have happened previously:

var a = {
	valueOf: function(){
		alert('a');
		return 1;
	}
};

var b = {
	valueOf: function(){
		alert('b');
		return 1;
	}
};

a<b
>> alert('a')
>> alert('b')
>> false

a>b
>> alert('b')
>> alert('a')
>> false

for .. in order

When looping through the properties of an object the order in which they were returned was left up to the implementation – now it’s required that the properties be returned in the order in which they were created. The final result would allow for the following, intuitive, result:

var obj = {1: 2, p: 'hi', '_':'under'};
for ( var i in obj )
	alert(i);
>> alert('1')
>> alert('p')
>> alert('_')

Implementations since JavaScript 1 have generally done it this way (and implementations that haven’t have found that web pages generally require this convention). Thus, it’s being made expressly clear now that this is the case.

Posted: October 31st, 2007


Subscribe for email updates

16 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.