skip to main |
skip to sidebar
RSS Feeds
ASP.NET, JavaScript, Oracle and SQL articles and code.
ASP.NET, JavaScript, Oracle and SQL articles and code.
1:41 AM
Posted by Michael Heliso
I always felt the need to have in JavaScript a more robust set of collections, like those from .NET: ArrayList, Dictionary, strong typed collections. So, some time ago I have decided to implement them everything having as base the JavaScript array object. The code I assume is self explanatory except the class definition which makes use of the custom pattern presented earlier on this blog. It shouldn’t matter too much because it’s very easy for you to implement same functionality using any desired inheritance pattern, like Base2 and Prototype. I think it’s a matter of copy/paste in most cases. You will notice that I didn’t use any special tricks in the code, just the well known JavaScript array object methods and properties. I did not use closures in this case so the ‘_array ‘ property it is consider private base on ‘_’ notation. Using closures eats up more resources so I preferred to avoid them in his case. If you have any questions feel free to post them and I’ll try to give you an answer as fast as possible. You can download the source from HERE.
if (typeof (MG) == 'undefined') throw ("MG.Core.js is required!"); if (typeof (MG.Collections) == 'undefined') MG.Collections = {}; MG.Collections.IComparer = function() { throw ("IComparer is an interface. Interfaces can't be instantiated directly!"); }; MG.Collections.IComparer.prototype = { Compare: function(object1, object2) { } } /******************************************************************************/ // IList interface definition. /******************************************************************************/ MG.Collections.IList = function() { throw ("IList is an interface. Interfaces can't be instantiated directly!"); }; MG.Collections.IList.prototype = { ___name: "IList", Add: function(object) { }, Clear: function() { }, Contains: function(object) { }, Remove: function(object) { }, IsReadOnly: Boolean, Item: function(index) { } }; /******************************************************************************/ // ICollection interface definition. /******************************************************************************/ MG.Collections.ICollection = function() { throw ("ICollection is an interface. Interfaces can't be instantiated directly!"); }; MG.Collections.ICollection.prototype = { ___name: "ICollection", CopyTo: function(array, arrayIndex) { }, Count: function() { } }; /******************************************************************************/ // IDictionary interface definition. /******************************************************************************/ MG.Collections.IDictionary = function() { throw ("IDictionary is an interface. Interfaces can't be instantiated directly!"); }; MG.Collections.IDictionary.prototype = { ___name: "IDictionary", Add: function(key, value) { }, Clear: function() { }, Contains: function(key) { }, Remove: function(key) { }, IsReadOnly: Boolean, Item: function(key) { } } /******************************************************************************/ // ArrayList class definition. // Implements interfaces: ICollection /******************************************************************************/ MG.Collections.ArrayList = MG.Class.Create( { _array: null, IsReadOnly: Boolean, constructor: function() { this._array = []; this.IsReadOnly = false; }, Add: function(object) { if (!this.IsReadOnly) this._array.push(object); else throw ("ArrayList is read only! Check IsReadOnly value."); }, Clear: function() { if (!this.IsReadOnly) this._array = []; else throw ("ArrayList is read only! Check IsReadOnly value."); }, Contains: function(object) { for (var index = 0; index < this._array.length; index++) { if (this._array[index] == object) return true; } return false; }, CopyTo: function(array, arrayIndex) { if (!array) throw ("Destination array is null!"); if (arrayIndex < 0 || arrayIndex > array.length) throw ("Index of destination array out of bound! Index value is: " + arrayIndex); for (var i = this._array.length - 1; i >= 0; i--) array.splice(arrayIndex, 0, this._array[i]); }, Remove: function(object) { if (!this.IsReadOnly) { for (var index = 0; index < this._array.length; index++) { if (this._array[index] == object) this._array.splice(index, 1); } } else throw ("ArrayList is read only! Check IsReadOnly value."); }, Count: function() { return this._array.length; }, Item: function(index) { if (index < 0 || index >= this._array.length) throw ("Index out of bound! Index value is: " + index); return this._array[index]; }, IndexOf: function(object) { for (var index = 0; index < this._array.length; index++) { if (this._array[index] == object) return index; } return -1; }, LastIndexOf: function(object) { var lastIndex = -1; for (var index = 0; index < this._array.length; index++) { if (this._array[index] == object) lastIndex = index; } return lastIndex; }, RemoveAt: function(index) { if (!this.IsReadOnly) { if (index < 0 || index >= this._array.length) throw ("Index out of bound! Index value is: " + index); this._array.splice(index, 1); } else throw ("ArrayList is read only! Check IsReadOnly value."); }, RemoveRange: function(index, Count) { if (!this.IsReadOnly) { if (index < 0 || index >= this._array.length) throw ("Index out of bound! Index value is: " + index); if (Count < 0 || (Count + index) > this._array.length) throw ("Range out of bound! Range value is: " + Count); this._array.splice(index, Count); } else throw ("ArrayList is read only! Check IsReadOnly value."); }, InsertAt: function(index, object) { if (!this.IsReadOnly) { if (index < 0 || index >= this._array.length) throw ("Index out of bound! Index value is: " + index); this._array.splice(index, 0, object); } else throw ("ArrayList is read only! Check IsReadOnly value."); }, InsertRange: function(index, _ICollection) { if (!this.IsReadOnly) { if (index < 0 || index >= this._array.length) throw ("Index out of bound! Index value is: " + index); var _newarray = _ICollection.GetRange(0, _ICollection.Count()); for (var i = 0; i < _newarray.length; i++) this.InsertAt(index, _newarray[i]); } else throw ("ArrayList is read only! Check IsReadOnly value."); }, GetRange: function(index, Count) { if (index < 0 || index >= this._array.length) throw ("Index out of bound! Index value is: " + index); if (Count < 0 || (Count + index) > this._array.length) throw ("Range out of bound! Range value is: " + Count); var arrayList = new ArrayList(); arrayList._array = this._array.slice(index, (Count + index)); return arrayList; }, Reverse: function() { if (!this.IsReadOnly) this._array.reverse(); else throw ("ArrayList is read only! Check IsReadOnly value."); }, Sort: function() { this._array.sort(); } }, null, [MG.Collections.ICollection]); /******************************************************************************/ // DictionaryEntry class definition. /******************************************************************************/ MG.Collections.DictionaryEntry = MG.Class.Create( { key: null, value: null, constructor: function(key, value) { this.key = key; this.value = value; } }); /******************************************************************************/ // Dictionary class definition. // Implements interfaces: IDictionary // ICollection /******************************************************************************/ MG.Collections.Dictionary = MG.Class.Create( { _dictionary: null, IsReadOnly: Boolean, constructor: function() { this._dictionary = []; this.IsReadOnly = false; }, Add: function(key, value) { if (!this.IsReadOnly) { if (this.Contains(key)) throw ("Dictionary does not allow duplicate keys!"); var dicEntry = new MG.Collections.DictionaryEntry(key, value); this._dictionary.push(dicEntry); } else throw ("Dictionary is read only! Check IsReadOnly value."); }, Clear: function() { if (!this.IsReadOnly) this._dictionary = []; else throw ("Dictionary is read only! Check IsReadOnly value."); }, Contains: function(key) { for (var index = 0; index < this._dictionary.length; index++) { if (this._dictionary[index].key == key) return true; } return false; }, Remove: function(key) { if (!this.IsReadOnly) { for (var index = 0; index < this._dictionary.length; index++) { if (this._dictionary[index].key == key) this._dictionary.splice(index, 1); } } else throw ("Dictionary is read only! Check IsReadOnly value."); }, Item: function(key) { if (!key) throw ("Invalid key! Key value is: " + key); for (var index = 0; index < this._dictionary.length; index++) { if (this._dictionary[index].key == key) return this._dictionary[index].value; } return null; }, CopyTo: function(array, arrayIndex) { if (!array) throw ("Destination array is null!"); if (arrayIndex < 0 || arrayIndex > array.length) throw ("Index of destination array out of bound! Index value is: " + arrayIndex); for (var i = this._dictionary.length - 1; i >= 0; i--) array.splice(arrayIndex, 0, this._dictionary[i]); }, Count: function() { return this._dictionary.length; }, Keys: function() { var keys = []; for (var index = 0; index < this._dictionary.length; index++) keys.push(this._dictionary[index].key); return keys.reverse(); }, Values: function() { var values = []; for (var index = 0; index < this._dictionary.length; index++) values.push(this._dictionary[index].value); return values.reverse(); }, IndexOf: function(key) { var keys = []; for (var index = 0; index < this._dictionary.length; index++) { if (this._dictionary[index].key == key) return index; } }, InsertAt: function(index, key, value) { if (!this.IsReadOnly) { if (index < 0 || index >= this._dictionary.length) throw ("Index out of bound! Index value is: " + index); var dicEntry = new MG.Collections.DictionaryEntry(key, value); this._dictionary.splice(index, 0, dicEntry); } else throw ("Dictionary is read only! Check IsReadOnly value."); }, Reverse: function() { if (!this.IsReadOnly) this._dictionary.reverse(); else throw ("Dictionary is read only! Check IsReadOnly value."); } }, null, [MG.Collections.IDictionary, MG.Collections.ICollection]); /******************************************************************************/ // Comparer class definition. // Implements interfaces: IComparer /******************************************************************************/ MG.Collections.Comparer = MG.Class.Create({ constructor: function() { }, Compare: function(object1, object2) { var result = false; var type = typeof object1; if (type !== typeof object2) throw ("Object 'object1' doesn't have same type as object 'object2'!"); else if (type === "object") { switch (object1.constructor) { case Array: { if (object1.length === object2.length) { for (var index = 0; index < object1.length; index++) { result = this.Compare(object1[index], object2[index]); if (!result) break; } } } break; case Dictionary: { if (object1.Count() === object2.Count()) { var keys = object1.Keys(); for (var index = 0; index < keys.length; index++) { if (object2.Contains(keys[index])) { result = this.Compare(object1.Item(keys[index]), object2.Item(keys[index])); if (!result) break; } else { result = false; break; } } } } break; case ArrayList: { if (object1.Count() === object2.Count()) { for (var index = 0; index < object1.Count(); index++) { result = this.Compare(object1.Item(index), object2.Item(index)); if (!result) break; } } } break; default: { if (object1 === object2) result = true; } break; } } switch (type) { case "string": case "number": case "boolean": if (object1 === object2) result = true; break; } return result; } }, null, [MG.Collections.IComparer]); MG.Collections.TypedCollection = MG.Class.Create({ Type: null, Browser: null, constructor: function(type) { var _type = typeof type; if (_type && _type === "function") this.Type = type; else throw ("The 'type' parameter must be a function object."); this.Browser = MG.Browser.getInstance(); }, Add: function() { var key = null; var value = null; if (arguments.length == 2) { key = arguments[0]; value = arguments[1]; } else if (arguments.length == 1) value = arguments[0]; else throw ("Invalid number of parameters. Number of parameters expected is two or one."); if (this.Browser.NS) { if (value.constructor !== this.Type.constructor) throw ("The 'value' parameter doesn't have same type as this collection."); } else if (this.Browser.IE) { if (value.constructor !== this.Type) throw ("The 'value' parameter doesn't have same type as this collection."); } if (!this.IsReadOnly) { if (key) { var dicEntry = new MG.Collections.DictionaryEntry(key, value); this._dictionary.push(dicEntry); } else { var dicEntry = new MG.Collections.DictionaryEntry("key", value); this._dictionary.push(dicEntry); } } else throw ("Dictionary is read only! Check IsReadOnly value."); }, Item: function() { if (!arguments.length == 1) throw ("Invalid number of parameters. Number of parameters expected is two or one."); var arg = arguments[0]; var type = typeof arg; var value = null; if (type == "string") value = this.___Item(arg); else if (type == "number") { if (this._dictionary.length > arg) value = this._dictionary[arg].value; else throw ("Index is out of range."); } return value; } }, MG.Collections.Dictionary, null);
November 17, 2010 at 6:33:00 PM PST
This looks very useful, but I can't find the "MG.Browser" class.
You're download link is broken - can you fix the link or post the source?
Thanks for a great post.
November 17, 2010 at 11:34:00 PM PST
Hi Dav0id, the link is fixed now.
December 6, 2010 at 10:21:00 AM PST
Dec. 6, 2010 link is down.
December 6, 2010 at 10:53:00 AM PST
Sorry, just fixed it now. You can try again when you have time.
March 30, 2011 at 3:57:00 AM PDT
as a programmer i say a very big thanks to you!!!!!!!!!!!