Generate a Hash from string in Javascript

JavascriptHash

Javascript Problem Overview


I need to convert strings to some form of hash. Is this possible in JavaScript?

I'm not utilizing a server-side language so I can't do it that way.

Javascript Solutions


Solution 1 - Javascript

String.prototype.hashCode = function() {
  var hash = 0, i, chr;
  if (this.length === 0) return hash;
  for (i = 0; i < this.length; i++) {
    chr   = this.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
};

Source: http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/

Solution 2 - Javascript

Many of the answers here are the same String.hashCode hash function taken from Java. It dates back to 1981 from Gosling Emacs, is extremely weak, and makes zero sense performance-wise in modern JavaScript. In fact, implementations could be significantly faster by using ES6 Math.imul, but no one took notice. We can do much better than this, at essentially identical performance.

Here's one I did—cyrb53, a simple but high quality 53-bit hash. It's quite fast, provides very good* hash distribution, and because it outputs 53 bits, has significantly lower collision rates compared to any 32-bit hash. Also, you can ignore SA's CC license as it's public domain on my GitHub.

const cyrb53 = function(str, seed = 0) {
    let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
    for (let i = 0, ch; i < str.length; i++) {
        ch = str.charCodeAt(i);
        h1 = Math.imul(h1 ^ ch, 2654435761);
        h2 = Math.imul(h2 ^ ch, 1597334677);
    }
    h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
    h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
    return 4294967296 * (2097151 & h2) + (h1>>>0);
};

*It is roughly similar to the well-known MurmurHash/xxHash algorithms. It uses a combination of multiplication and Xorshift to generate the hash, but not as thorough. As a result it's faster than either would be in JavaScript and significantly simpler to implement, but may not pass all tests in SMHasher. This is not a cryptographic hash function, so don't use this for security purposes.

Like any proper hash, it has an avalanche effect, which basically means small changes in the input have big changes in the output making the resulting hash appear more 'random':

"501c2ba782c97901" = cyrb53("a")
"459eda5bc254d2bf" = cyrb53("b")
"fbce64cc3b748385" = cyrb53("revenge")
"fb1d85148d13f93a" = cyrb53("revenue")

You can optionally supply a seed (unsigned integer, 32-bit max) for alternate streams of the same input:

"76fee5e6598ccd5c" = cyrb53("revenue", 1)
"1f672e2831253862" = cyrb53("revenue", 2)
"2b10de31708e6ab7" = cyrb53("revenue", 3)

Technically, it is a 64-bit hash, that is, two uncorrelated 32-bit hashes computed in parallel, but JavaScript is limited to 53-bit integers. If convenient, the full 64-bit output can be used by altering the return statement with a hex string or array.

return [h2>>>0, h1>>>0];
// or
return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or 
return 4294967296n * BigInt(h2) + BigInt(h1);

Be aware that constructing hex strings drastically slows down batch processing. The array is much more efficient, but obviously requires two checks instead of one. I also included BigInt, which should be slightly faster than String, but still much slower than Array or Number.


Just for fun, here's TinySimpleHash, the smallest hash I could come up with that's still decent. It's a 32-bit hash in 89 chars with better quality randomness than even FNV or DJB2:

TSH=s=>{for(var i=0,h=9;i<s.length;)h=Math.imul(h^s.charCodeAt(i++),9**9);return h^h>>>9}

Solution 3 - Javascript

EDIT

based on my jsperf tests, the accepted answer is actually faster: http://jsperf.com/hashcodelordvlad

ORIGINAL

if anyone is interested, here is an improved ( faster ) version, which will fail on older browsers who lack the reduce array function.

hashCode = function(s){
  return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);				
}

one-liner arrow function version :

hashCode = s => s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)

Solution 4 - Javascript

>Note: Even with the best 32-bit hash, collisions will occur sooner or later.
> >The hash collision probablility can be calculated as 1 - e ^ (-k(k-1) / 2N, aproximated as k^2 / 2N (see here). This may be higher than intuition suggests:
Assuming a 32-bit hash and k=10,000 items, a collision will occur with a probablility of 1.2%. For 77,163 samples the probability becomes 50%! (calculator).
I suggest a workaround at the bottom.

In an answer to this question Which hashing algorithm is best for uniqueness and speed?, Ian Boyd posted a good in depth analysis. In short (as I interpret it), he comes to the conclusion that Murmur is best, followed by FNV-1a.
Java’s String.hashCode() algorithm that esmiralha proposed seems to be a variant of DJB2.

  • FNV-1a has a a better distribution than DJB2, but is slower
  • DJB2 is faster than FNV-1a, but tends to yield more collisions
  • MurmurHash3 is better and faster than DJB2 and FNV-1a (but the optimized implementation requires more lines of code than FNV and DJB2)

Some benchmarks with large input strings here: http://jsperf.com/32-bit-hash
When short input strings are hashed, murmur's performance drops, relative to DJ2B and FNV-1a: http://jsperf.com/32-bit-hash/3

So in general I would recommend murmur3.
See here for a JavaScript implementation: https://github.com/garycourt/murmurhash-js

If input strings are short and performance is more important than distribution quality, use DJB2 (as proposed by the accepted answer by esmiralha).

If quality and small code size are more important than speed, I use this implementation of FNV-1a (based on this code).

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as 
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

Improve Collision Probability

As explained here, we can extend the hash bit size using this trick:

function hash64(str) {
    var h1 = hash32(str);  // returns 32 bit (as 8 byte hex string)
    return h1 + hash32(h1 + str);  // 64 bit (as 16 byte hex string)
}

Use it with care and don't expect too much though.

Solution 5 - Javascript

Based on accepted answer in ES6. Smaller, maintainable and works in modern browsers.

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));

EDIT (2019-11-04):

one-liner arrow function version :

const hashCode = s => s.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0)

// test console.log(hashCode('Hello!'))

Solution 6 - Javascript

I'm a bit surprised nobody has talked about the new SubtleCrypto API yet.

To get an hash from a string, you can use the subtle.digest method :

function getHash(str, algo = "SHA-256") {
  let strBuf = new TextEncoder().encode(str);
  return crypto.subtle.digest(algo, strBuf)
    .then(hash => {
      window.hash = hash;
      // here hash is an arrayBuffer, 
      // so we'll connvert it to its hex version
      let result = '';
      const view = new DataView(hash);
      for (let i = 0; i < hash.byteLength; i += 4) {
        result += ('00000000' + view.getUint32(i).toString(16)).slice(-8);
      }
      return result;
    });
}

getHash('hello world')
  .then(hash => {
    console.log(hash);
  });

Solution 7 - Javascript

This is a refined and better performing variant, and matches Java's implementation of the standard object.hashCode() for CharSequence.

String.prototype.hashCode = function() {
    var hash = 0, i = 0, len = this.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
    }
    return hash;
};

Here is also one that returns only positive hashcodes:

String.prototype.hashcode = function() {
    return this.hashCode()+ 2147483647 + 1;
};

And here is a matching one for Java that only returns positive hashcodes:

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}

Without prototype for those that do not want to attach it to String :

function hashCode(str) {
    var hash = 0, i = 0, len = str.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + str.charCodeAt(i++)) << 0;
    }
    return hash;
}

function hashcode(str) {
    hashCode(str) + 2147483647 + 1;
}

Enjoy!

Solution 8 - Javascript

If it helps anyone, I combined the top two answers into an older-browser-tolerant version, which uses the fast version if reduce is available and falls back to esmiralha's solution if it's not.

/**
 * @see http://stackoverflow.com/q/7616461/940217
 * @return {number}
 */
String.prototype.hashCode = function(){
	if (Array.prototype.reduce){
		return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
	} 
	var hash = 0;
	if (this.length === 0) return hash;
	for (var i = 0; i < this.length; i++) {
		var character  = this.charCodeAt(i);
		hash  = ((hash<<5)-hash)+character;
		hash = hash & hash; // Convert to 32bit integer
	}
	return hash;
}

Usage is like:

var hash = "some string to be hashed".hashCode();

Solution 9 - Javascript

Here is a compact ES6 friendly readable snippet

const stringHashCode = str => {
  let hash = 0
  for (let i = 0; i < str.length; ++i)
    hash = Math.imul(31, hash) + str.charCodeAt(i)

  return hash | 0
}

Solution 10 - Javascript

UUID v3 and UUID v5 actually are hashes for a given input string.

  • UUID v3 is based on MD5,
  • UUID v5 is based on SHA-1.

So, the most obvious choice would be to go for UUID v5.

Fortunately, there is a popular npm package, which includes all UUID algorithms.

npm install uuid

To actually generate a UUID v5, you need a unique namespace. This namespace acts like a seed, and should be a constant, to assure that for a given input the output will always be the same. Ironically, you should generate a UUID v4 as a namespace. And the easiest way to do so, is using some online tool.

Once you've got a namespace, you're all set.

import { v5 as uuidv5 } from 'uuid';

const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
const hash = uuidv5('input', MY_NAMESPACE);

If your input string will always be an URL for instance, then there are some default namespaces which you can use.

const hashForURL = uuidv5('https://www.w3.org/', uuidv5.URL);

Solution 11 - Javascript

Thanks to the example by mar10, I found a way to get the same results in C# AND Javascript for an FNV-1a. If unicode chars are present, the upper portion is discarded for the sake of performance. Don't know why it would be helpful to maintain those when hashing, as am only hashing url paths for now.

C# Version

private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5;   // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193;     // 16777619

// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
    // byte[] arr = Encoding.UTF8.GetBytes(s);      // 8 bit expanded unicode array
    char[] arr = s.ToCharArray();                   // 16 bit unicode is native .net 

    UInt32 hash = FNV_OFFSET_32;
    for (var i = 0; i < s.Length; i++)
    {
        // Strips unicode bits, only the lower 8 bits of the values are used
        hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
        hash = hash * FNV_PRIME_32;
    }
    return hash;
}

// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
    return unchecked((int)s.HashFnv32u());
}

JavaScript Version

var utils = utils || {};

utils.FNV_OFFSET_32 = 0x811c9dc5;

utils.hashFnv32a = function (input) {
    var hval = utils.FNV_OFFSET_32;
    
    // Strips unicode bits, only the lower 8 bits of the values are used
    for (var i = 0; i < input.length; i++) {
        hval = hval ^ (input.charCodeAt(i) & 0xFF);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }

    return hval >>> 0;
}

utils.toHex = function (val) {
    return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}

Solution 12 - Javascript

My quick (very long) one liner based on FNV's Multiply+Xor method:

my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);

Solution 13 - Javascript

A fast and concise one which was adapted from here:

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}

Solution 14 - Javascript

I'm kinda late to the party, but you can use this module: crypto:

const crypto = require('crypto');

const SALT = '$ome$alt';

function generateHash(pass) {
  return crypto.createHmac('sha256', SALT)
    .update(pass)
    .digest('hex');
}

The result of this function is always is 64 characters string; something like this: "aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"

Solution 15 - Javascript

I needed a similar function (but different) to generate a unique-ish ID based on the username and current time. So:

window.newId = ->
  # create a number based on the username
  unless window.userNumber?
    window.userNumber = 0
  for c,i in window.MyNamespace.userName
    char = window.MyNamespace.userName.charCodeAt(i)
    window.MyNamespace.userNumber+=char
  ((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()

Produces:

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc 

edit Jun 2015: For new code I use shortid: https://www.npmjs.com/package/shortid

Solution 16 - Javascript

SubtleCrypto.digest

> I’m not utilizing a server-side language so I can’t do it that way.

Are you sure you can’t do it that way?

Did you forget you’re using Javascript, the language ever-evolving?

Try SubtleCrypto. It supports SHA-1, SHA-128, SHA-256, and SHA-512 hash functions.


async function hash(message/*: string */) { const text_encoder = new TextEncoder; const data = text_encoder.encode(message); const message_digest = await window.crypto.subtle.digest("SHA-512", data); return message_digest; } // -> ArrayBuffer

function in_hex(data/*: ArrayBuffer */) {
	const octets = new Uint8Array(data);
	const hex = [].map.call(octets, octet => octet.toString(16).padStart(2, "0")).join("");
	return hex;
} // -> string

(async function demo() {
	console.log(in_hex(await hash("Thanks for the magic.")));
})();

Solution 17 - Javascript

I have combined the two solutions (users esmiralha and lordvlad) to get a function that should be faster for browsers that support the js function reduce() and still compatible with old browsers:

String.prototype.hashCode = function() {

	if (Array.prototype.reduce) {
		return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);   
	} else {

		var hash = 0, i, chr, len;
		if (this.length == 0) return hash;
		for (i = 0, len = this.length; i < len; i++) {
		chr   = this.charCodeAt(i);
		hash  = ((hash << 5) - hash) + chr;
		hash |= 0; // Convert to 32bit integer
		}
		return hash;
	}
};

Example:

my_string = 'xyz';
my_string.hashCode();

Solution 18 - Javascript

I went for a simple concatenation of char codes converted to hex strings. This serves a relatively narrow purpose, namely just needing a hash representation of a SHORT string (e.g. titles, tags) to be exchanged with a server side that for not relevant reasons can't easily implement the accepted hashCode Java port. Obviously no security application here.

String.prototype.hash = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.map.call(range, function(i) {
    return self.charCodeAt(i).toString(16);
  }).join('');
}

This can be made more terse and browser-tolerant with Underscore. Example:

"Lorem Ipsum".hash()
"4c6f72656d20497073756d"

I suppose if you wanted to hash larger strings in similar fashion you could just reduce the char codes and hexify the resulting sum rather than concatenate the individual characters together:

String.prototype.hashLarge = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.reduce.call(range, function(sum, i) {
    return sum + self.charCodeAt(i);
  }, 0).toString(16);
}

'One time, I hired a monkey to take notes for me in class. I would just sit back with my mind completely blank while the monkey scribbled on little pieces of paper. At the end of the week, the teacher said, "Class, I want you to write a paper using your notes." So I wrote a paper that said, "Hello! My name is Bingo! I like to climb on things! Can I have a banana? Eek, eek!" I got an F. When I told my mom about it, she said, "I told you, never trust a monkey!"'.hashLarge()
"9ce7"

Naturally more risk of collision with this method, though you could fiddle with the arithmetic in the reduce however you wanted to diversify and lengthen the hash.

Solution 19 - Javascript

If you want to avoid collisions you may want to use a secure hash like SHA-256. There are several JavaScript SHA-256 implementations.

I wrote tests to compare several hash implementations, see https://github.com/brillout/test-javascript-hash-implementations.

Or go to http://brillout.github.io/test-javascript-hash-implementations/, to run the tests.

Solution 20 - Javascript

Adding this because nobody did yet, and this seems to be asked for and implemented a lot with hashes, but it's always done very poorly...

This takes a string input, and a maximum number you want the hash to equal, and produces a unique number based on the string input.

You can use this to produce a unique index into an array of images (If you want to return a specific avatar for a user, chosen at random, but also chosen based on their name, so it will always be assigned to someone with that name).

You can also use this, of course, to return an index into an array of colors, like for generating unique avatar background colors based on someone's name.

function hashInt (str, max = 1000) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
      hash = ((hash << 5) - hash) + str.charCodeAt(i);
      hash = hash & hash;
    }
    return Math.round(max * Math.abs(hash) / 2147483648);
}

Solution 21 - Javascript

This generates a consistent hash based on any number of params passed in:

/**
 * Generates a hash from params passed in
 * @returns {string} hash based on params
 */
function fastHashParams() {
    var args = Array.prototype.slice.call(arguments).join('|');
    var hash = 0;
    if (args.length == 0) {
        return hash;
    }
    for (var i = 0; i < args.length; i++) {
        var char = args.charCodeAt(i);
        hash = ((hash << 5) - hash) + char;
        hash = hash & hash; // Convert to 32bit integer
    }
    return String(hash);
}

fastHashParams('hello world') outputs "990433808"

fastHashParams('this',1,'has','lots','of','params',true) outputs "1465480334"

Solution 22 - Javascript

The Jenkins One at a Time Hash is quite nice:

//Credits (modified code): Bob Jenkins (http://www.burtleburtle.net/bob/hash/doobs.html)
//See also: https://en.wikipedia.org/wiki/Jenkins_hash_function
//Takes a string of any size and returns an avalanching hash string of 8 hex characters.
function jenkinsOneAtATimeHash(keyString)
{
  let hash = 0;
  for (charIndex = 0; charIndex < keyString.length; ++charIndex)
  {
    hash += keyString.charCodeAt(charIndex);
    hash += hash << 10;
    hash ^= hash >> 6;
  }
  hash += hash << 3;
  hash ^= hash >> 11;
  //4,294,967,295 is FFFFFFFF, the maximum 32 bit unsigned integer value, used here as a mask.
  return (((hash + (hash << 15)) & 4294967295) >>> 0).toString(16)
};

Examples:

jenkinsOneAtATimeHash('test')
"31c25ec1"
jenkinsOneAtATimeHash('a')
"ca2e9442"
jenkinsOneAtATimeHash('0')
"6e3c5c6b"

You can also remove the .toString(16) part at the end to generate numbers:

jenkinsOneAtATimeHash2('test')
834821825
jenkinsOneAtATimeHash2('a')
3392050242
jenkinsOneAtATimeHash2('0')
1849449579

Note that if you do not need to hash a string or key specifically, but just need a hash generated out of thin air, you can use:

window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)

Examples:

window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
"6ba9ea7"
window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
"13fe7edf"
window.crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
"971ffed4"

and the same as above, you can remove the `.toString(16) part at the end to generate numbers:

window.crypto.getRandomValues(new Uint32Array(1))[0]
1154752776
window.crypto.getRandomValues(new Uint32Array(1))[0]
3420298692
window.crypto.getRandomValues(new Uint32Array(1))[0]
1781389127

Note: You can also generate multiple values at once with this method, e.g.:

window.crypto.getRandomValues(new Uint32Array(3))
Uint32Array(3) [ 2050530949, 3280127172, 3001752815 ]

Solution 23 - Javascript

Slightly simplified version of @esmiralha's answer.

I don't override String in this version, since that could result in some undesired behaviour.

function hashCode(str) {
	var hash = 0;
	for (var i = 0; i < str.length; i++) {
		hash = ~~(((hash << 5) - hash) + str.charCodeAt(i));
	}
	return hash;
}

Solution 24 - Javascript

I do not see any reason to use this overcomplicated crypto code instead of ready-to-use solutions, like object-hash library, or etc. relying on vendor is more productive, saves time and reduces maintenance cost.

Just use https://github.com/puleos/object-hash

var hash = require('object-hash');

hash({foo: 'bar'}) // => '67b69634f9880a282c14a0f0cb7ba20cf5d677e9'
hash([1, 2, 2.718, 3.14159]) // => '136b9b88375971dff9f1af09d7356e3e04281951'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFreesn&#246;wView Question on Stackoverflow
Solution 1 - JavascriptesmiralhaView Answer on Stackoverflow
Solution 2 - JavascriptbrycView Answer on Stackoverflow
Solution 3 - JavascriptlordvladView Answer on Stackoverflow
Solution 4 - Javascriptmar10View Answer on Stackoverflow
Solution 5 - JavascriptDeekshithView Answer on Stackoverflow
Solution 6 - JavascriptKaiidoView Answer on Stackoverflow
Solution 7 - JavascriptmjsView Answer on Stackoverflow
Solution 8 - JavascriptKyle FalconerView Answer on Stackoverflow
Solution 9 - JavascriptAmirheView Answer on Stackoverflow
Solution 10 - JavascriptbvdbView Answer on Stackoverflow
Solution 11 - JavascriptdjabrahamView Answer on Stackoverflow
Solution 12 - JavascriptJohn SmithView Answer on Stackoverflow
Solution 13 - JavascriptsoulmachineView Answer on Stackoverflow
Solution 14 - JavascriptAriel JiménezView Answer on Stackoverflow
Solution 15 - JavascriptjcollumView Answer on Stackoverflow
Solution 16 - JavascriptКонстантин ВанView Answer on Stackoverflow
Solution 17 - JavascriptFrankView Answer on Stackoverflow
Solution 18 - JavascriptswornabsentView Answer on Stackoverflow
Solution 19 - JavascriptbrilloutView Answer on Stackoverflow
Solution 20 - JavascriptNick SteeleView Answer on Stackoverflow
Solution 21 - JavascriptJohn DohertyView Answer on Stackoverflow
Solution 22 - JavascriptAndrewView Answer on Stackoverflow
Solution 23 - Javascriptcrazy2beView Answer on Stackoverflow
Solution 24 - JavascriptOleg AbrazhaevView Answer on Stackoverflow