简体   繁体   中英

Hashing JavaScript objects

I have a function that receives a list of JS objects as an argument. I need to store information about those objects in a private variable for future reference. I do not want to stuff a property into the objects themselves, I just want to keep it out of band in a dictionary. I need to be able to lookup metadata for an object in sub-linear time.

For this I need a hash function such that, for any two objects o1 and o2 ,

hash(o1) !== hash(o2) whenever o1 !== o2 .

A perfect example of such a hash function would be the memory address of the object, but I don't think JS exposes that. Is there a way?

Each object reference is different. Why not push the object onto an array? Traversing the array looking for an object reference might still perform better than inspecting each object in a recursive manor to generate a hash key.

function Dictionary() {
    var values = [];

    function contains(x) {
        var i = values.length;

        while(i--) {
            if (values[i] === x) {
                return true;
            }
        }

        return false;
    }

    function count() {
        return values.length;
    }

    function get(i) {
        return (i >= 0 && i < values.length) ? values[i] : null;
    }

    function set(o) {
        if (contains(o)) {
            throw new Error("Object already exists in the Dictionary");
        }
        else {
            return values.push(o) - 1;
        }
    }

    function forEach(callback, context) {
        for (var i = 0, length = values.length; i < length; i++) {
            if (callback.call(context, values[i], i, values) === false) {
                break;
            }
        }
    }

    return {
        get: get,
        set: set,
        contains: contains,
        forEach: forEach,
        count: count
    };
}

And to use it:

var objects = Dictionary();

var key = objects.set({});

var o = objects.get(key);

objects.contains(key); // returns true

objects.forEach(function(obj, key, values) {
    // do stuff
}, this);

objects.count(); // returns 1

objects.set(o); // throws an error

To store metadata about objects, you can use an WeakMap :

WeakMaps are key/value maps in which keys are objects.


Note that this API is still experimental and thus not widely supported yet (see support table ). There is a polyfill implementation which makes use of defineProperty to set GUIDs (see details here ).

Javascript does not provide direct access to memory (or to the file system for that matter).

You'd probably just want to create your properties/variables within the analysis (hash) function, and then return them to where the function was called from to be stored/persisted for later reference.

Thanks everyone who chipped in to reply. You all have convinced me that what I want to do is currently not possible in JavaScript.

There seem to be two basic compromises that someone with this use case can chose between:

  1. Linear search using ===

    === appears to be the only built-in way to distinguish between two identically-valued objects that have different references. (If you had two objects, o1 and o2 , and did a deep comparison and discovered that they were value-identical, you might still want to know if they're reference-identical. Besides === you could do something weird like add a property to o1 and see if showed up in o2 ).

  2. Add a property to the object.

    I didn't like this approach because there's no good reason why I should have to expose this information to the outside world. However, a colleague tipped me off to a feature that I didn't know about: Object.defineProperty. With this, I can alleviate my main concerns: first, that my id would show up, unwanted, during object enumeration, and second, that someone could inadvertently alter my id if there were to be a namespace collision.

So, in case anyone comes here wanting the same thing I wanted, I'm putting it up there for the record that I'm going to add a unique id using Object.defineProperty.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM