Set of objects in javascript

It's not possible for all objects, but if your object has a .toString() method implemented, it is:

var x = {toString: function(){ return 'foo'; }};
var y = {toString: function(){ return 'bar'; }};
var obj = {};
obj[x] = 'X';
obj[y] = 'Y';
console.log(obj);
// { foo: 'X', bar: 'Y' }

If you want to make this easier, make it a class:

function myObj(name){
   this.name = name;
}
myObj.prototype.toString = function(){ return this.name; }

var obj = {};
obj[new myObj('foo')] = 'X';
obj[new myObj('bar')] = 'Y';

Here's a mad suggestion ... key it on the result of JSON.stringify(object)


I'm answering my own question, but I came up with an alternative solution I thought was interesting and thought it would be useful to share it.

cwolves' answer gave me an idea. Providing an object's toString() method uniquely identifies the instance, properties of an object can be used to store a set of objects. Essentially, to store object x, you can use items[x.toString()] = x;. Note that the value is the object itself, so then the set of objects can be extracted by looking at all item's properties and dumping all the values in to an array.

Here's the class, which I call ObjectSet, in full. It requires objects are uniquely identified by their toString() method, which is OK for my purposes. add, remove and contains should all run in better than O(n) time - whatever javascript's property access efficiency is, which hopefully is either O(1) or O(n log n).

// Set of objects.  Requires a .toString() overload to distinguish objects.
var ObjectSet = function ()
{
    this.items = {};
    this.item_count = 0;
};

ObjectSet.prototype.contains = function (x)
{
    return this.items.hasOwnProperty(x.toString());
};

ObjectSet.prototype.add = function (x)
{
    if (!this.contains(x))
    {
        this.items[x.toString()] = x;
        this.item_count++;
    }

    return this;
};

ObjectSet.prototype.remove = function (x)
{
    if (this.contains(x))
    {
        delete this.items[x.toString()];
        this.item_count--;
    }

    return this;
};

ObjectSet.prototype.clear = function ()
{
    this.items = {};
    this.item_count = 0;

    return this;
};

ObjectSet.prototype.isEmpty = function ()
{
    return this.item_count === 0;
};

ObjectSet.prototype.count = function ()
{
    return this.item_count;
};

ObjectSet.prototype.values = function ()
{
    var i, ret = [];

    for (i in this.items)
    {
        if (this.items.hasOwnProperty(i))
            ret.push(this.items[i]);
    }

    return ret;
};

ES6 provides a native Set:

let s = new Set();
let a = {};
let b = {};

s.add(a);

console.log(s.has(a));  // true
console.log(s.has(b));  // false