2

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);
4

2 回答 2

1

好吧,通过运行你的代码,我发现alert(my_set.size); 了定义中的一个小错误, Set.prototype.size = function(){ return this.n; }; 所以,size 是一种方法。因此,您应该将其作为方法调用以返回正确的结果,例如 var result = my_set.size()

于 2013-06-26T11:01:22.070 回答
0

显然,您不能将新属性分配给 JS 中的基元。这个怎么样:

var objectId = (function() {
  var next = 100; // start assigning objectids at this value.     
  var ids = {};
  return function(o){
    if (!ids.hasOwnProperty(o)) // if the object has no id
        ids[o] = next++; // assign it the next available
    return ids[o];
  };  
}) ();
于 2013-06-26T11:19:24.293 回答