histarray – An Experiment with Getters and Setters

While doing an experiment with Getters and Setters I whipped together a small lib for a versioning array, the histarray. So far tested only in Firefox 3, it utilizes __defineGetter__(someNumber, function(){}) to return an element from an internal array (the history). Its push method will either overwrite the current revision if it is not the last, or push a new revision into the history. A Setter is also defined, so no matter where in the time line you currently are, that element will be updated.

function histarray()
{
	for(var i = 0; i < arguments.length; i++)
		this._add(arguments[i], i);

	this.__defineSetter__('revision', function(v)
	{
		return (v > this.length) ?
			this.revision :
			this._revision = v;
	});
	this.__defineGetter__('revision', function()
	{
		return this._revision;
	});
	this.__defineGetter__('prev', function()
	{
		return (this.revision != 0) ?
			(function(self)
			{
				var a = Array();
				for(var i in self._elements)
					a.push(self._elements[i][self.revision - 1]);
				return a;
			})(this) :
			null;
	});
	this.__defineGetter__('nxt', function()
	{
		return (this.revision < this.revisions) ?
			(function(self)
			{
				var a = Array();
				for(var i in self._elements)
					a.push(self._elements[i][self.revision + 1]);
				return a;
			})(this) :
			null;
	});
};

histarray.prototype =
{
	length: 0,
	revisions: 0,
	_elements: Array(),
	_revision: 0,
	_add: function(e, i)
	{
		this._elements[i] = (function(e,self)
		{
			var a = Array();
			for(var i = 0; i < self.revisions; i++)
				a.push(null);
			a.push(e);
			return a;
		})(e,this);
		this.__defineGetter__(i, function()
		{
			return this._elements[i][this.revision];
		});

		this.__defineSetter__(i, function(v)
		{
			return this._elements[i][this.revision] = v;
		});
		this.length = i + 1;
	},
	// push csv or a single array
	push: function()
	{
		if(typeof arguments[0] == 'object')
			this.push.apply(this, arguments[0]);
		else
		{
			if(this.revision == this.revisions)
			{
				this.revision++;
				this.revisions++;
			}
			for(var i = 0; i < arguments.length; i++)
			{
				if(arguments[i] == null) continue;

				if(this._elements[i])
					this._elements[i][this.revision] = arguments[i];
				else
					this._add(arguments[i], i);
			}
		}
		return this.length;
	}
};
// creates a new histarray.
var ha = new histarray('e1', 'e2', 'e3');
// this is now just like a normal array, ha[0] == 'e1'
// now using push does not add a new element, but instead adds a new revision
ha.push('e1v2', 'e2v2', 'e3v2')
// now ha[0] == 'e1v2' and ha.revision == 1 and ha.prev[0] == 'e1'
// if we change the revision back to 0
ha.revision = 0;
// ha[0] == 'e1', ha.nxt[0] == 'e1v2'
// with the revision still at 0, we can update an old element
ha[0] = 'e1a';
// this just changes the first revision of the first element.

Not certain is will be useful for anything in particular. But I still have a couple ideas to add, and am interested in hear what people have to say about this.

Comments are closed.