views:

62

answers:

2

I have a situation, where I need to create a new JavaScript object that is inherited from Array. I am using the following code:

// Create constructor function.
var SpecialArray = function () {};

// Create intermediate function to create closure upon Array's prototype.
// This prevents littering of native Array's prototype.
var ISpecialArray = function () {};
ISpecialArray.prototype = Array.prototype;
SpecialArray.prototype = new ISpecialArray();
SpecialArray.prototype.constructor = SpecialArray;


// Use Array's push() method to add two elements to the prototype itself.
SpecialArray.prototype.push('pushed proto 0', 'pushed proto 1');

// Use [] operator to add item to 4th position
SpecialArray.prototype[4] = 'direct [] proto to 4';

// Create new instance of Special Array
var x = new SpecialArray();

// Directly add items to this new instance.
x.push('pushed directly on X');
x[9] = 'direct [] to 9'

console.log(x, 'length: ' + x.length);

Quite interestingly, the [] operation seem to be useless and the console output is:

["pushed proto 0", "pushed proto 1", "pushed directly on X"] length: 3

What am I missing here?

+3  A: 

This is one of those that always trips people up. The length property only applies to the ordered elements. You can't extend an array then insert an arbitrary non-sequitous key and expect it to work. This is because the relationship between the length property and the array contents is broken once you extend the array. Pointy's link above does a very good job of explaining this in more detail.

To prove this add this to the end of your example:

console.log(x[4]);

As you can see your entry is present and correct, it's just not part of the ordered array.

Like everything else in javascript the Array object is just a Associative Array with string keys. Non numerical, non sequitous keys are hidden to fool you into thinking it's a 'proper' numerically indexed array.

This strange mixed design of the Array object does mean you can do some strange and wonderful things like storing ordered and unordered information in the same object. I'm not saying this is a good idea, I'm just saying it's possible.

As you will have noticed by now when iterating structures like this the non sequitous keys don't appear which makes sense for the general use case of arrays for ordered information. It's less useful, or in fact useless when you want to get keyed info. I would venture that if ordering is unimportant you should use an object not an array. If you need both ordered and unordered store an array as a property in an object.

Ollie Edwards
@Ollie: I guess this is the perfect reasoning for the current behavioral paradigm of JavaScript Array.
Shamasis Bhattacharya
+4  A: 

It is not possible to subclass the Array class and use t this way. The best solution for you is to extend just the array class and use it as it is. There are two other options that I do not like but they exist

budinov.com
Also (very recent, and thorough): http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/
Pointy
yes very good explnation + something new for me :)
budinov.com
@budinov.com:Very interestingly, in the above two posts you linked, a lot of people grumbled that it is a waste to subclass array and that there is no need for this.However, I have a situation where I need to modify the prototype of the array to hold ordered elements so that, in case a child object does not have a specific element, it will be returned from prototype.So, subclassing Array is required as well, in case I stick to the architecture I am planning.Sadly the main requirement (performance) is actually degraded in the above two alternate hacks.Thanks @budinov.com
Shamasis Bhattacharya