206

Possible Duplicate:
Generate a Hash from string in Javascript/jQuery

Can anyone suggest a simple (i.e. tens of lines of code, not hundreds of lines) hash function written in (browser-compatible) JavaScript? Ideally I'd like something that, when passed a string as input, produces something similar to the 32 character hexadecimal string that's the typical output of MD5, SHA1, etc. It doesn't have to be cryptographically secure, just reasonably resistant to collisions. (My initial use case is URLs, but I'll probably want to use it on other strings in the future.)

7
  • Is there a particular reason you don't want to use sha1? there are a plethora of examples of this in js Commented May 25, 2011 at 10:05
  • 4
    I want to package this with some other code that's about 50 lines long; I don't want my hash function to be 10x as long as the "interesting" bits. Commented May 25, 2011 at 10:28
  • I think I understand your point now. Is there a reason you cannot use an include? Do you really need to use only one file? Commented May 25, 2011 at 10:32
  • 5
    Yes I could, and I'm prepared to do that if necessary, but I'd preferably like something self-contained that I can post as a gist on github or similar. Commented May 25, 2011 at 10:44
  • 6
    An implementation of Jenkins's one-at-a-time hash window.hashJoaat=function(b){for(var a=0,c=b.length;c--;)a+=b.charCodeAt(c),a+=a<<10,a^=a>>6;a+=a<<3;a^=a>>11;return((a+(a<<15)&4294967295)>>>0).toString(16)}; Commented Oct 15, 2016 at 15:59

5 Answers 5

228

I didn't verify this myself, but you can look at this JavaScript implementation of Java's String.hashCode() method. Seems reasonably short.

It has been long accepted that modifying built-in prototypes is bad practice, so use a plain function like this:

/**
 * Returns a hash code from a string
 * @param  {String} str The string to hash.
 * @return {Number}    A 32bit integer
 * @see http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
 */
function hashCode(str) {
    let hash = 0;
    for (let i = 0, len = str.length; i < len; i++) {
        let chr = str.charCodeAt(i);
        hash = (hash << 5) - hash + chr;
        hash |= 0; // Convert to 32bit integer
    }
    return hash;
}
Sign up to request clarification or add additional context in comments.

22 Comments

SHA1 and MD5 are ridiculously slow. I did a bunch of comparison tests, and this implementation of Java's hash proved fastest, and as few collisions (on relatively uniform data) as any of the others I tried. Very short and sweet.
Really cool! Only thing is this pollutes the prototype of String with a non-Ecmascript method. I would rewrite it as a stand-alone function, maybe put it in your util library.
Another thing is that it creates a global variable i, because he forgot the var keyword in the loop. But those issues can easily be fixed.
Micro-optimization: remove the if (this.length == 0) {return hash} block since it's redundant anyway (the for is executed while length is positive, otherwise 0 is returned by default). Do I miss something?
In one line: Array.from(str).reduce((hash, char) => 0 | (31 * hash + char.charCodeAt(0)), 0) (where str is the string)
|
20

There are many realizations of hash functions written in JS. For example:

If you don't need security, you can also use base64 which is not hash-function, has not fixed output and could be simply decoded by user, but looks more lightweight and could be used for hide values: http://www.webtoolkit.info/javascript-base64.html

2 Comments

base64 encoding of a string is more or less the same length as the original string; I'd like something that's shorter, like a hash.
base64 is even longer than the input, by the way to clarify that a bit more.
6

Simple object hasher:

(function () {
    Number.prototype.toHex = function () {
        var ret = ((this<0?0x8:0)+((this >> 28) & 0x7)).toString(16) + (this & 0xfffffff).toString(16);
        while (ret.length < 8) ret = '0'+ret;
        return ret;
    };
    Object.hashCode = function hashCode(o, l) {
        l = l || 2;
        var i, c, r = [];
        for (i=0; i<l; i++)
            r.push(i*268803292);
        function stringify(o) {
            var i,r;
            if (o === null) return 'n';
            if (o === true) return 't';
            if (o === false) return 'f';
            if (o instanceof Date) return 'd:'+(0+o);
            i=typeof o;
            if (i === 'string') return 's:'+o.replace(/([\\\\;])/g,'\\$1');
            if (i === 'number') return 'n:'+o;
            if (o instanceof Function) return 'm:'+o.toString().replace(/([\\\\;])/g,'\\$1');
            if (o instanceof Array) {
                r=[];
                for (i=0; i<o.length; i++) 
                    r.push(stringify(o[i]));
                return 'a:'+r.join(';');
            }
            r=[];
            for (i in o) {
                r.push(i+':'+stringify(o[i]))
            }
            return 'o:'+r.join(';');
        }
        o = stringify(o);
        for (i=0; i<o.length; i++) {
            for (c=0; c<r.length; c++) {
                r[c] = (r[c] << 13)-(r[c] >> 19);
                r[c] += o.charCodeAt(i) << (r[c] % 24);
                r[c] = r[c] & r[c];
            }
        }
        for (i=0; i<r.length; i++) {
            r[i] = r[i].toHex();
        }
        return r.join('');
    }
}());

The meat here is the stringifier, which simply converts any object into a unique string. hashCode then runs over the object, hashing together the characters of the stringified object.

For extra points, export the stringifier and create a parser.

2 Comments

any reason not to use JSON.stringify?
March 2012. I couldn't, at the time, assume that JSON worked correctly in a certain browser. Also, JSON drops functions, so they wouldn't be hashable using JSON as your stringifier.
3

Check out this MD5 implementation for JavaScript. Its BSD Licensed and really easy to use. Example:

md5 = hex_md5("message to digest")

5 Comments

I had found that, and it would work, but I was hoping for something smaller and simpler. Also, isn't the "message digest" the result of hex_md5(message)?
Yes digest is the result, the parameter is the message you want to digest - hence "message to digest".
But anyway in which way you want the implementation to be simpler? That implementation is a simple JavaScript file with less then 400 lines. Do you just want a single function or what?
That makes more sense to me now; previously you had something like hex_md5("message_digest") = "fb6cecc85a100197ae3ad68d1f9f2886", right? (Can't find the revision of your answer.)
Yes, I corrected that. But can you elaborate on the simplicity issue: in which way you want a simpler library?
2
// Simple but unreliable function to create string hash by Sergey.Shuchkin [t] gmail.com
// alert( strhash('http://www.w3schools.com/js/default.asp') ); // 6mn6tf7st333r2q4o134o58888888888
function strhash( str ) {
    if (str.length % 32 > 0) str += Array(33 - str.length % 32).join("z");
    var hash = '', bytes = [], i = 0, j = 0, k = 0, a = 0, dict = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','1','2','3','4','5','6','7','8','9'];
    for (i = 0; i < str.length; i++ ) {
        ch = str.charCodeAt(i);
        bytes[j++] = (ch < 127) ? ch & 0xFF : 127;
    }
    var chunk_len = Math.ceil(bytes.length / 32);   
    for (i=0; i<bytes.length; i++) {
        j += bytes[i];
        k++;
        if ((k == chunk_len) || (i == bytes.length-1)) {
            a = Math.floor( j / k );
            if (a < 32)
                hash += '0';
            else if (a > 126)
                hash += 'z';
            else
                hash += dict[  Math.floor( (a-32) / 2.76) ];
            j = k = 0;
        }
    }
    return hash;
}

2 Comments

This script will pollute the global scope with the following variables: j, k, a. The reason for this is because they are not a part of the var statement, merely a part of the expression that is evaluated to var i. Instead, use var i, j, k, a; i = j = k = a = 0;.
Yes, the JS is poorly written, but it appears to directly address the OP's question and provides example code. Thank you!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.