The Generic class is a strongly typed list of objects that
can be easily referenced by index. Many .NET developers benefit from the
Generic class because they are easily searched, sorted, and manipulated.
I find myself developing in JavaScript from an object
orientated perspective, even though it is more of a procedural language, with
influences of C# leaving its trace. I first started with this generic class
below and started noticing great benefits: the code is more easily readable,
.NET developers who are not familiar with JavaScript tend to not have problems
learning when they can code similar to C#, and code re-usability.
Listing 1
//--------------------------------------------------------------
// Class: List
// Author: Ryan Estes
// Description: Contructs an object that references a collection
// of objects.
// Methods: Add,Contains,Count,Find,FindIndex,FindAll,Items,GetRange,Sort,Reverse,
// GetRange,Remove,RemoveAll,ToString, GetType, Equals,Concat
//
//---------------------------------------------------------------
// Constructor: (),(Object obj)
function List()
{
this._arrItems = (arguments.length == 1)? new Array(arguments[0]) : new Array();
// Param: (Object obj)
// Return: void
this.Add = function(obj) {
this._arrItems[this._arrItems.length] = obj;
}
// Property : Accessor
this.Count = function() {
return this._arrItems.length;
}
// Param: (List<T>)
// Return: void
this.Concat = function() {
try
{
if(objlist.GetType() != "Library.List")
{
throw "(Exception: List_Concat_0) Object of Library.List type expected";
}
this._arrItems = this._arrItems.concat(objlist.Items());
}
catch (e)
{
throw "(Exception: List_Concat_1) Invalid paramter type";
}
}
// Param: string
// Return: boolean
this.Contains = function(str) {
for(var i = 0; i < this._arrItems.length; i++)
{
alert(str);
alert(this._arrItems[i]);
if(str == this._arrItems[i])
return true;
}
return false;
}
this.Equals = function(oList) {
try
{
if(oList.GetType() == this.GetType())
{
if(this._arrItems.length == oList.Items().length)
{
for(i = 0; i < this._arrItems.length; i++)
{
if(this._arrItems[i] != oList.Items()[i])
{
return false;
}
}
return true;
}
}
}
catch (e)
{
throw "(Exception: List_Equals_0) Invalid parameter type";
}
return false;
}
// Params: Predicate<T>
// Return: int
// Description: Returns the number of occurrences
this.Find = function(pfnc) {
var intOccurences = 0;
for(var i = 0; i < this._arrItems.length; i++)
{
try
{
if(pfnc(this._arrItems[i]))
{
intOccurences++;
}
}
catch (e)
{
throw "(Exception: List_Find_0) " + e.message;
}
}
return intOccurences;
}
// Params: Predicate<T>
// Return: int
// Description: Returns the index of the first occurrence
this.FindIndex = function(pfnc) {
for(i = 0; i < this._arrItems.length; i++)
{
try
{
if(pfnc(this._arrItems[i]))
{
return i;
}
}
catch (e)
{
throw "(Exception: List_FindIndex_0) " + e.message;
}
}
return -1;
}
// Params: Predicate<T>
// Return: List<Object>
// Description: Returns a list of matching objects
this.FindAll = function(pfnc) {
var objList = new List();
for(var i = 0; i < this._arrItems.length; i++)
{
try
{
if(pfnc(this._arrItems[i]))
{
objList.Add(this._arrItems[i]);
}
}
catch (e)
{
throw "(Exception: List_FindAll_0) " + e.message;
}
}
return objList;
}
// Return: List<Object>
// Description: Returns a partition of a list.
this.GetRange = function(intStartIndex,intCount) {
var intEndIndex = intStartIndex + (intCount - 1) ;
var objlist = new List();
if(intStartIndex < 0 || intEndIndex < 0)
throw "(Exception: List_GetRange_0) Index must be a non-negative integer";
if(intEndIndex > this._arrItems.length - 1)
throw "(Exception: List_GetRange_1) Index Out of Range";
if(intStartIndex > intEndIndex)
throw "(Exception: List_GetRange_2)" +
" Start index must be less than or equal to the end index";
for(var i = intStartIndex; i < intEndIndex + 1; i++)
{
objlist.Add(this._arrItems[i]);
}
return objlist;
}
this.GetType = function() {
return "Library.List";
}
// Property : Accessor
this.Items = function() {
return this._arrItems;
}
// Return: void
this.Reverse = function() {
this._arrItems = this._arrItems.reverse()
}
// Return: void
this.Remove = function(intIndex) {
if(intIndex < 0)
throw "(Exception: List_Remove_0) Index must be a non-negative integer";
if(intIndex > this._arrItems.length)
throw "(Exception: List_Remove_1) Index Out of Range";
var olist = new List();
for(var i = 0; i < this._arrItems.length; i++)
{
if(i != intIndex)
olist.Add(this._arrItems[i]);
}
this._arrItems = olist.Items();
}
// Return: void
this.RemoveAll = function() {
this._arrItems = new Array();
}
// Return: void
this.Sort = function() {
this._arrItems = this._arrItems.sort();
}
// Params: (), (string delimiter)
this.ToString = function() {
var strDelimiter = (arguments.length == 1)? arguments[0] : "";
return this._arrItems.join(strDelimiter);
}
}
There you have it, the generic class in a JavaScript
nutshell. For clarification, below are some samples of how this class can be
used.
Listing 2
var oList1 = new List();
// Count()
alert(oList1.Count());
// Add()
oList1.Add("ASP");
oList1.Add("DOT");
oList1.Add("NET");
alert(oList1.Count());
var oList2 = new List("ASP");
// Equals()
alert(oList1.Equals(oList2));
// GetType()
alert(oList2.GetType() == oList1.GetType());
// Reverse()
alert(oList1.Reverse());
// Find()
var fNumberOfASP = function(str) {
return str == "ASP";
}
alert(oList1.Find(fNumberOfASP) + "" );
// List of Objects
function Coordinate(intX,intY)
{
this.X = intX;
this.Y = intY;
}
var oList3 = new List();
oList3.Add(new Coordinate(0,0));
oList3.Add(new Coordinate(1,1));
alert(oList3.GetRange(0,1).Count());