I have the following code (which is actually creating a Set class, or to be more explicit is creating an unordered collection of values, with no duplicates).
Unfortunately it doesn't work ==> running it in a debugger I see that the following line is returning "undefined": o[prop] = Set._v2s.next++;
I think this is happening because o="o", so that I can't use this Set class with strings.
Any idea how to modify the code such that I can use it with strings (like in my attached example)?
Here is the code:
function Set(){ // the constructor
this.values = {}; // an empty object that will keep all the set elements'
// names as properties
this.n = 0; // #values in the set
this.add.apply(this, arguments); // when initially build the set then add all the arguments of the constructor into the set
}
// Add each of the arguments of the constructor to the set
Set.prototype.add = function(){
for (var i=0; i<arguments.length; i++){ // for each argument of the constructor
var val = arguments[i];
var str = Set._v2s(val); // transform the value to a string
if (!this.values.hasOwnProperty(str)){ // If not already in the set
this.values[str]=val; // Load the element in the set
this.n++;
}
}
return this; // support chained method call
};
// Remove each of the arguments from the set
Set.prototype.remove = function(){
for (var i=0; i<arguments.length; i++){ // for each argument
var str = Set._v2s(arguments[i]);
if (this.values.hasOwnProperty(str)){ // If the element is in the set already
delete this.values[str];
this.n--; // Delete it
}
}
return this;
};
// Return true if the set contains a value; false otherwise
Set.prototype.contains = function(value){
return this.values.hasOwnProperty(Set._v2s(value));
};
// Return the size of the set
Set.prototype.size = function(){
return this.n;
};
// Call function f on the specified context for each element of the set.
Set.prototype.foreach = function(f,context){
for (var s in this.values)
if (this.values.hasOwnProperty(s)) // ignore inherited props
f.call(context,this.values[s]); // call f on the value
};
// This internal function maps any JavaScript value to a unique string.
Set._v2s = function(val){
switch (val){
case undefined: return 'u'; // special primitive
case null: return 'n';
case true: return 't';
case false: return 'f';
default: switch(typeof val){
case 'number': return '#' + val; // numbers get the # prefix
case 'string': return '@' + objectId(val);
}
}
};
// for any object, return a string ( a unique one per object, and if applied repeatedly on the same object will return the same string. The key technique is to add a (nonenumerable and read-only in ES5) property to object o.
function objectId(o){
var prop = "|**objectid**|"; // private property name for storing ids
if (!o.hasOwnProperty(prop)) // if the object has no id
o[prop] = Set._v2s.next++; // assign it the next available
return o[prop];
};
Set._v2s.next = 100; // start assigning objectids at this value.
var my_set = new Set("o","pojo");
alert(my_set.size);