Wednesday, May 21, 2008

Stack and ArrayObject - How to create an advanced subclassed Array constructor

Another problem left to solve is that after subclassing an Array one would like the return types of Array.prototype methods to be of the subclass type instead of its superclass type Array.

This comment is, basically, a summary of the reason I created the ArrayObject constructor.

Today, I have totally rewrote that constructor, using a Stack instance as prototype.

The Stack constructor aim is to subclass the Array one in the most compatible, and light, way.

For this reason, I have not changed native Array behaviours, those that return an Array, for example, instead of a Stack instance (concat, filter, map, slice).

But the good thing of Stack, is that now we can create our subclassed Array constructor, without affecting the native Array object, and adding, modifying, or removing, whatever we want.

For example, to solve the problem described on top of this post, I have simply modified inherited Stack methods, returning an instance of ArrayObject, every time we use, for example, a concat.

var a = new ArrayObject(1,2,3),
b = new ArrayObject(7,8,9),
c = a.concat([4,5,6], b);
alert(c); // 1,2,3,4,5,6,7,8,9
alert(c instanceof ArrayObject); // true

The same behaviour is obtained using slice, map, or filter, so we have our constructor, with our prototype, loads of possibilities.

The valueOf revenge


In ArrayObject, I have changed valueOf behaviour. This method returns basically the same information of toString, but it is used internally in a lot of cases.
One of them, is when you compare, sum, multiply, divide, whatever two variables.

// how to know if an ArrayObject has more elements than other one
var a = new ArrayObject(1,2,3),
b = new ArrayObject(4);
alert(a > b); // false

Above example calls in an implicit way the valueOf prototype methods.
Since latter one returns the length of the ArrayObject, and since b is an ArrayObject with length of 4, the a variable, with only 3 elements, will fail that kind of check.
Another interesting example that could allow us to write less code is this kind of check to know if an ArrayObject has some element:

var a = new ArrayObject(),
b = new ArrayObject(1,2,3);
if(-a)
alert("a has some element");
if(-b)
alert(b); // 1,2,3

Above example shows how to use in a quick and dirty way the valueOf behaviour with an ArrayObject instance. It is the same of:

if(a.length)
alert("a has some element");
if(b.length)
alert(b); // 1,2,3


The "to" prototype and the public static create


In the old ArrayObject version, I used a to prototype to convert a variable into a different one, using a constructor.
The main purpose of the Stack constructor, is to avoid Array.prototype methods assignment, as should be for every other native constructor to avoid problems between libraries.
In this version, the to prototype is only for ArrayObject:

var a = new ArrayObject(4,5,6),
b = [1,2,3].concat(a.to(Array));

In this way we could convert an ArrayObject in every other Array like compatible instance, such Array, or Stack itself.

To invert the conversion, we could use the factory pattern via create.

var a = [1,2,3],
b = ArrayObject.create(a).reverse();
alert(b instanceof ArrayObject); // true


I am working to fix last little problems with my code, but I think both Stack and ArrayObject could be used witout problems, and starting right now ;)

No comments:

Post a Comment