views:

3859

answers:

5

Basically what I'm trying to do is create an object of unique objects, a set. I had the brilliant idea of just using a JS object with objects for the property names. Such as,

set[obj] = true;

This works, to a point. It works great with string and numbers, but with other objects, they all seem to "hash" to the same value and access the same property. Is there some kind of way I can generate a unique hash value for an object? How do strings and numbers do it, can I override the same behavior? Can someone please explain this to me?

A: 

Javascript objects can only use strings as keys (anything else is converted to a string).

You could, alternatively, maintain an array which indexes the objects in question, and use its index string as a reference to the object. Something like this:

var ObjectReference = [];
ObjectReference.push(obj);

set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;

Obviously it's a little verbose, but you could write a couple of methods that handle it and get and set all willy nilly.

Edit:

Your guess is fact -- this is defined behaviour in JS -- specifically a toString conversion occurs meaning that you can can define your own toString function on the object that will be used as the property name. - olliej

This brings up another interesting point; you can define a toString method on the objects you want to hash, and that can form their hash identifier.

eyelidlessness
another option would be to give each object a random value as it's hash - maybe a random number + total ticks - then have a set of functions to add/remove the object from the array.
Sugendran
This will fail if you add the same object twice. It will think that it is different.
Daniel X Moore
"This will fail if you add the same object twice. It will think that it is different."Good point. A solution could be to subclass Array for ObjectReference, hooking a duplicate check into push(). I don't have time to edit for this solution now, but I hope I'll remember to later.
eyelidlessness
It'd be nice if downvoters would explain why they downvote.
eyelidlessness
A: 

If you truly want set behavior (I'm going by Java knowledge), then you will be hard pressed to find a solution in JavaScript. Most developers will recommend a unique key to represent each object, but this is unlike set, in that you can get two identical objects each with a unique key. The Java API does the work of checking for duplicate values by comparing hash code values, not keys, and since there is no hash code value representation of objects in JavaScript, it becomes almost impossible to do the same. Even the Prototype JS library admits this shortcoming, when it says:

"Hash can be thought of as an associative array, binding unique keys to values (which are not necessarily unique)..."

http://www.prototypejs.org/api/hash

hal10001
+1  A: 

The JS spec defines indexed property access as performing a toString conversion on the index name. eg.

myObject[myProperty] = ...;

is the same as

myObject[myProperty.toString()] = ...;

This is necessary as in JS

myObject["someProperty"]

is the same as

myObject.someProperty

And yes, it makes me sad as well :-(

olliej
+4  A: 

The easiest way to do this is to give each of your objects it's own unique toString method.

(function() {
    var id = 0;

    /*global MyObject */
    MyObject = function() {
      this.objectId = '<#MyObject:' + (id++) + '>';
      this.toString= function() {
        return this.objectId;
      };
    };
  })();

I had the same problem and this solved it perfectly for me with minimal fuss, and was a lot easier that re-implementing some fatty Java style Hashtable and adding equals() and hashCode() to your object classes. Just make sure that you don't also stick a string '<#MyObject:12> into your hash or it will wipe out the entry for your exiting object with that id.

Now all my hashes are totally chill. I also just posted a blog entry a few days ago about this exact topic.

Daniel X Moore
A: 

Take a look here: jshashtable 2.1 - http://www.timdown.co.uk/jshashtable/

MatteoSp