You need push, count, you might want to have all arrays methods / accesssors / iterators.
What's more, you 'll get some speed boost if you let your collection be an array.
So best solution is to inherit from array, and to
have your objects be just real arrays : nothing should be
defined on the object, everything on its prototype.
-->> You'll get the speed and all features of arrays for free.
The function looks like :
function MsgObjCollection() { /* nothing */ };
var SO_pr = ( MsgObjCollection.prototype = [] ) ;
And then, to define count, sent and received on the prototype, use Object.defineProperty not to pollute enumeration, and also to have getters/setters :
Object.defineProperty(SO_pr, 'sent', { get : function() {
var cnt = 0;
this.forEach( function(x) { if (x.source == 'Sent') cnt++; });
return cnt; } } );
Object.defineProperty(SO_pr, 'received', { get : function() {
var cnt = 0;
this.forEach( function(x) { if (x.source == 'Received') cnt++; });
return cnt; } } );
Object.defineProperty(SO_pr, 'count', { get : function() { return this.length } ,
set : function (x) { this.length = x } });
Notice that since the Msg collection's prototype is a new array, you do not pollute array's prototype when changing MsgObjCollection's prototype.
The Sent and Received property you wish are more complex : they act as a view on the underlying object.
One thing you can do is to have them return a new array built out of the right items of the original array.
I prefer, though, to build a wrapper around the original array 1) to allow modification through this view and 2) to avoid garbage creation.
The fiddle is here : http://jsfiddle.net/cjQFj/1/
Object.defineProperty(SO_pr, 'Sent',
{ get : function() { return getWrapper('Sent', this); } } ) ;
Object.defineProperty(SO_pr, 'Received',
{ get : function() { return getWrapper('Received', this); } } ) ;
function getWrapper(wrappedProp, wrappedThis) {
var indx = 0, wp=null;
// try to find a cached wrapper
while (wp = getWrapper.wrappers[indx++] ) {
if (wp.wthis === this && wp.wprop==wrappedProp) return wp.wrapper;
};
// no wrapper : now build, store, then return a new one
var newWrapper = {
get count() { return (wrappedProp=='Sent') ? wrappedThis.sent : wrappedThis.received },
unshift : function () { if (this.count == 0) return null;
var indx=0;
while (wrappedThis[indx].source != wrappedProp ) indx++;
var popped = wrappedThis[indx];
while (indx<wrappedThis.length-1) {wrappedThis[indx]=wrappedThis[indx+1]; indx++; }
wrappedThis.length--;
return popped;
}
};
getWrapper.wrappers.push({ wthis : wrappedThis, wprop : wrappedProp, wrapper : newWrapper });
return newWrapper;
};
getWrapper.wrappers = [];
Now just a little test :
var myColl = new MsgObjCollection();
myColl.push({ source : 'Sent', message : 'hello to Jhon' });
myColl.push({ source : 'Received' , message : 'hi from Kate' });
myColl.push({ source : 'Sent', message : 'hello to Kate' });
myColl.push({ source : 'Received' , message : 'Reply from Jhon' });
myColl.push({ source : 'Received' , message : 'Ho, i forgot from Jhon' });
console.log('total number of messages : ' + myColl.count);
console.log('sent : ' + myColl.sent + ' Sent.count ' + myColl.Sent.count);
console.log('received : ' + myColl.received + ' Received.count ' + myColl.Received.count);
console.log('removing oldest sent message ');
var myLastSent = myColl.Sent.unshift();
console.log ('oldest sent message content : ' + myLastSent.message);
console.log('total number of messages : ' + myColl.count);
console.log('sent : ' + myColl.sent + ' Sent.count ' + myColl.Sent.count);
console.log('received : ' + myColl.received + ' Received.count ' + myColl.Received.count);
Output : >>
total number of messages : 5
sent : 2 Sent.count 2
received : 3 Received.count 3
removing oldest sent message
oldest sent message content : hello to Jhon
total number of messages : 4
sent : 1 Sent.count 1
received : 3 Received.count 3
The annoying part is that those view properties are not arrays, but since you cannot overload [] operator, you cannot have a fully transparent view on the original array, (i.e. : myBox.Sent[i] that would be exactly the i-th sent message ) so at some point you might want to create arrays on the fly for some operations.