As Most of the Javascript Set implementations have flaw in comparing objects, as javascript compares identities of the objects, not actual values. Here is my implementation with true object value comparison.
/*Constructor: Takes array or implicit null as an argument*/
function Set(arr)
{
if(arr == null)
this._array = [];
else
{
if(arr.constructor == Array)
this._array = arr;
else
this._array = [arr];
}
}
Set.prototype =
{
/*Compares the type of the objects and actual values, rather than object identity*/
_compare : function(i, j )
{
var itype = typeof(i);
var jtype = typeof(j);
/*Both are primitives, compare directly*/
if(itype != 'object' && jtype != 'object')
return i === j;
/*Both are objects*/
if(itype == 'object' && jtype == 'object')
{
if(i.constructor != j.constructor) /*Check whether, they are of same type */
return false;
for(var k in i) /*For each value compare recursively*/
{
if(! k in j || !this._compare(i[k], j[k])) return false;
}
return true;
}
/*comparison of primitive form and object form*/
if(itype == 'object')
return i.valueOf() === j;
return i === j.valueOf();
},
/*Returns values of the set*/
values: function()
{
return this._array;
},
/*Returns the size of the set*/
size : function()
{
return this._array.length;
},
/*Checks whether Set has an element or not*/
contains : function(n)
{
for(var i in this._array)
{
if(this._compare(this._array[i], n) )
return true;
}
return false;
},
/*adds the element to the set, if it is not there */
add: function(n)
{
if(!this.contains(n))
this._array.push(n);
},
/*removes the element from the set, if it is there*/
remove: function(n)
{
for(var i in this._array)
{
if(this._compare(this._array[i], n) )
{
this._array.splice(i, 1);
return;
}
}
},
/*Returns new set containing union of the two*/
union: function(other)
{
var result;
var arr;
if(this.size() > other.size())
{
result = new Set( this._array.slice(0) );
arr = other._array;
}
else
{
result = new Set(other._array.slice(0));
arr = this._array;
}
for(var i in arr)
{
if( !result.contains(arr[i]))
result.add(arr[i]);
}
return result;
},
/*Returns new set containing intersection of the two*/
intersection: function(other)
{
var result = new Set();
var arr, set;
if(this.size() < other.size())
{
arr = this._array;
set = other;
}
else
{
arr = other._array;
set = this;
}
for(var i in arr)
{
if( set.contains(arr[i]))
result.add(arr[i]);
}
return result;
},
/*Checks this is subset of other*/
isSubsetOf: function(other)
{
for(var i in this._array)
{
if(!other.contains(this._array[i]))
return false;
}
return true;
},
/*Checks whether two sets are equal*/
equals : function(other)
{
return this.isSubsetOf(other) && other.isSubsetOf(this);
},
/*Subtracts other from this*/
minus : function(other)
{
var arr = this._array.slice(0);
for(var i in arr )
{
if(other.contains(arr[i]))
arr.splice(i, 1);
}
return new Set(arr);
}
};