Inconsistent array literals
Back at the Rich Web Experience, I helped lead a “birds of a feather” group discussion on JavaScript. In that discussion, someone called me a JavaScript expert. I quickly explained that I don’t like being called an expert because it implies that I know everything about JavaScript, which I don’t. I then went on to share some anecdotes of things that I learned in the past year. Indeed, every time I think I know a lot, I stumble across something else that I didn’t know before. I’d like to share something I learned today about JavaScript.
Late last year, a discussion between myself and Steve Carlson (also on the My Yahoo! team) led to us discovering that array literals could be specified with empty values by putting commas in without values, such as:
var values = [,,,,,];
This creates an array whose values are all undefined. The fun part is, once again, with browser differences. In Internet Explorer, this creates an array of six items. There are five commas so it assumes that you’re separated six values…makes sense, right? In all the other browsers (Firefox, Safari, Opera), it creates an array of five items. Why does this happen? This can be seen more clearly in the following example:
var values = [1,2,];
In Internet Explorer, this creates a three-item array where the values are 1, 2, and undefined. In the other browsers, it creates a two-item array where the values are 1 and 2. So which of these two groups is correct? By default, one would assume that IE is wrong since it usually is.
ECMA-262 (p.41) indicates that a dangling comma is legal syntax. Commas in array initializers are represented by the Elision production. Without going into all of the technical mumbo jumbo, the specification basically states that each Elision adds 1 to the array’s length property. This means that, as usual, IE’s implementation is incorrect since five commas should equal five items, not six.
It’s really frustrating to me that now, eight years after the third edition of ECMA-262 was finalized that browsers still don’t have this specification implemented perfectly.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




7 Comments
>This creates an array whose values are all undefined.
Values? The missing array element contributes to the length of the array and increases the index of subsequent elements (the only property value that elisions affect is the length property!), elided array elements are not defined. Mz’s implementation is incorrect.
Array.prototype[1] = ‘foo’;
var a = [0,,2];
alert(a[1]); //-> ‘foo’ in IE, ‘undefined’ in Mz (incorrect)
>In Internet Explorer, this creates an array of six items.
The length property is 6 (incorrect, should be 5), elements (‘items’) are not defined (correct).
Zeroglif on September 10th, 2007 at 3:20 am
Zeoglif: in your example you redefine first item, so Mozilla’s implementation is more logical, at least for me.
Nicholas: use [,,,undefined] to get the array of the same length in all browsers.
JCurtis on September 10th, 2007 at 3:44 am
@Zeroglif – I’m not entirely sure what point you’re trying to prove. Undefined is a value in JavaScript, and I believe that Firefox is doing the correct thing due to this from ECMA-262:
"Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in
the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after
another comma), the missing array element contributes to the length of the Array and increases the index
of subsequent elements. Elided array elements are not defined."
This seems to indicate that, once again, IE is incorrect.
@JCurtis – Yes, that’s because you don’t have a dangling comma. I’m not looking for a workaround, just trying to point out an error in implementation.
Nicholas C. Zakas on September 10th, 2007 at 10:21 pm
Nicholas,
IE:
- length is 6 –> incorrect
- elements are not defined (no properties; no values) –> correct
Mz:
- length is 5 –> correct
- elements are defined (value type Undefined) –> incorrect
I’m trying to prove that actually they both are buggy…
https://bugzilla.mozilla.org/show_bug.cgi?id=260106
http://groups.google.com.ph/group/comp.lang.javascript/browse_thread/thread/ddea13e8c6ddea98/6eabac0d4d00a968
Zeroglif on September 11th, 2007 at 5:39 am
This is the same bug that makes IE throw a fit at the following:
{
asdf:’foo’,
}
because it interprets this as:
{
asdf:’foo’,
undefined
}
which is wrong.
@Zeroglif
You’re right. Both browsers are a little wrong. IE is wrong in the number of items it creates. Moz is wrong in creating a member with a value of undefined, instead of just not creating a member.
In other words:
IE treats [,1,] as [,1,,].
Mz treats [,1,] as [undefined,1,].
It’s kind of like the difference between:
// error! v is not defined!
function(){ alert(v); }
// alerts "undefined"
function(){ var v; alert(v); }
In the second case, v is "defined" but its value is "undefined". In the first case, v is not defined at all, and the execution throws an exception.
Elided values should be actually *missing* according to the spec; instead, Mz creates a member in the array and sets it to the special value "undefined".
IMO, elision in arrays is one of those profoundly misguided things that shouldn’t be there in the first place. It’s pretty much never useful, and only serves to make code more complicated.
Isaac Z. Schlueter on September 11th, 2007 at 4:18 pm
In a related concept, there’s a difference between using "in" and "delete" and manually setting an object’s member to undefined.
http://foohack.com/2007/06/javascript-style-tip-use-in-and-delete/
Using delete makes it go completely away. Setting it to undefined just removes its value.
Isaac Z. Schlueter on September 11th, 2007 at 5:55 pm
Okay, so I understand what everyone is saying now. This really is the classic confusion between the special value "undefined" and something just plain being undefined.
@Isaac – I agree that elision in arrays is, for all intents and purposes, not useful at all. As for using "delete", to be a bit more complete, delete removes instance properties/methods; if a property of the same name exists on the prototype then it will show up using "in". For example:
function MyType(){
this.color = "red";
}
MyType.prototype.color = "blue";
var o = new MyType();
alert("color" in o);
alert(o.color); //red
delete o.color;
alert("color" in o);
alert(o.color); //blue
In this case, the "color" property is never truly removed from the object because it searches up to the prototype for its definition.
Nicholas C. Zakas on September 11th, 2007 at 6:33 pm
Comments are automatically closed after 14 days.