Is there any kind of hash code function in JavaScript?

后端 未结 20 1167
慢半拍i
慢半拍i 2020-12-04 09:59

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

相关标签:
20条回答
  • 2020-12-04 10:31

    I will try to go a little deeper than other answers.

    Even if JS had better hashing support it would not magically hash everything perfectly, in many cases you will have to define your own hash function. For example Java has good hashing support, but you still have to think and do some work.

    One problem is with the term hash/hashcode ... there is cryptographic hashing and non-cryptographic hashing. The other problem, is you have to understand why hashing is useful and how it works.

    When we talk about hashing in JavaScript or Java most of the time we are talking about non-cryptographic hashing, usually about hashing for hashmap/hashtable (unless we are working on authentication or passwords, which you could be doing server-side using NodeJS ...).

    It depends on what data you have and what you want to achieve.

    Your data has some natural "simple" uniqueness:

    • The hash of an integer is ... the integer, as it is unique, lucky you !
    • The hash of a string ... it depends on the string, if the string represents a unique identifier, you may consider it as a hash (so no hashing needed).
    • Anything which is indirectly pretty much a unique integer is the simplest case
    • This will respect: hashcode equal if objects are equal

    Your data has some natural "composite" uniqueness:

    • For example with a person object, you may compute a hash using firstname, lastname, birthdate, ... see how Java does it: Good Hash Function for Strings, or use some other ID info that is cheap and unique enough for your usecase

    You have no idea what your data will be:

    • Good luck ... you could serialize to string and hash it Java style, but that may be expensive if the string is large and it will not avoid collisions as well as say the hash of an integer (self).

    There is no magically efficient hashing technique for unknown data, in some cases it is quite easy, in other cases you may have to think twice. So even if JavaScript/ECMAScript adds more support, there is no magic language solution for this problem.

    In practice you need two things: enough uniqueness, enough speed

    In addition to that it is great to have: "hashcode equal if objects are equal"

    • https://en.wikipedia.org/wiki/Hash_table#Collision_resolution
    • Relationship between hashCode and equals method in Java
    0 讨论(0)
  • 2020-12-04 10:32

    What you described is covered by Harmony WeakMaps, part of the ECMAScript 6 specification (next version of JavaScript). That is: a set where the keys can be anything (including undefined) and is non-enumerable.

    This means it's impossible to get a reference to a value unless you have a direct reference to the key (any object!) that links to it. It's important for a bunch of engine implementation reasons relating to efficiency and garbage collection, but it's also super cool for in that it allows for new semantics like revokable access permissions and passing data without exposing the data sender.

    From MDN:

    var wm1 = new WeakMap(),
        wm2 = new WeakMap();
    var o1 = {},
        o2 = function(){},
        o3 = window;
    
    wm1.set(o1, 37);
    wm1.set(o2, "azerty");
    wm2.set(o1, o2); // A value can be anything, including an object or a function.
    wm2.set(o3, undefined);
    wm2.set(wm1, wm2); // Keys and values can be any objects. Even WeakMaps!
    
    wm1.get(o2); // "azerty"
    wm2.get(o2); // Undefined, because there is no value for o2 on wm2.
    wm2.get(o3); // Undefined, because that is the set value.
    
    wm1.has(o2); // True
    wm2.has(o2); // False
    wm2.has(o3); // True (even if the value itself is 'undefined').
    
    wm1.has(o1);   // True
    wm1.delete(o1);
    wm1.has(o1);   // False
    

    WeakMaps are available in current Firefox, Chrome and Edge. They're also supported in Node v7 , and in v6 with the --harmony-weak-maps flag.

    0 讨论(0)
  • 2020-12-04 10:33

    My solution introduces a static function for the global Object object.

    (function() {
        var lastStorageId = 0;
    
        this.Object.hash = function(object) {
            var hash = object.__id;
    
            if (!hash)
                 hash = object.__id = lastStorageId++;
    
            return '#' + hash;
        };
    }());
    

    I think this is more convenient with other object manipulating functions in JavaScript.

    0 讨论(0)
  • 2020-12-04 10:33

    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

    0 讨论(0)
  • 2020-12-04 10:35

    The easiest way to do this is to give each of your objects its 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.

    0 讨论(0)
  • 2020-12-04 10:36

    The JavaScript specification defines indexed property access as performing a toString conversion on the index name. For example,

    myObject[myProperty] = ...;
    

    is the same as

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

    This is necessary as in JavaScript

    myObject["someProperty"]
    

    is the same as

    myObject.someProperty
    

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

    0 讨论(0)
提交回复
热议问题