Instantly share code, notes, and snippets.

Embed
What would you like to do?
ID - a unique ID/name generator for JavaScript
// Generate unique IDs for use as pseudo-private/protected names.
// Similar in concept to
// <http://wiki.ecmascript.org/doku.php?id=strawman:names>.
//
// The goals of this function are twofold:
//
// * Provide a way to generate a string guaranteed to be unique when compared
// to other strings generated by this function.
// * Make the string complex enough that it is highly unlikely to be
// accidentally duplicated by hand (this is key if you're using `ID`
// as a private/protected name on an object).
//
// Use:
//
// var privateName = ID();
// var o = { 'public': 'foo' };
// o[privateName] = 'bar';
var ID = function () {
// Math.random should be unique because of its seeding algorithm.
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
// after the decimal.
return '_' + Math.random().toString(36).substr(2, 9);
};
@JustMikey

This comment has been minimized.

JustMikey commented Feb 20, 2014

Thank you, it was helpful :)

@themesociety

This comment has been minimized.

themesociety commented Feb 21, 2014

Thanks, working great. :)

@carlosocarvalho

This comment has been minimized.

carlosocarvalho commented Feb 26, 2014

Thank you.

@niklas-r

This comment has been minimized.

niklas-r commented Mar 7, 2014

This doesn't always match /_\w{9}/ and I'm not sure why. If someone could help me understand why that is I'd be grateful.

@ezakto

This comment has been minimized.

ezakto commented May 12, 2014

@nikias-r
Sometimes .toString() returns a string representation with length shorter than 9. ie:

var number = Math.random() // 0.9394456857981651
number.toString(36); // '0.xtis06h6'
var id = number.toString(36).substr(2, 9); // 'xtis06h6'
id.length >= 9; // false

This doesn't happen in all browsers (this example can be replicated in firefox, but not in chrome).

@javestruz

This comment has been minimized.

javestruz commented May 30, 2014

Thanks!

@ksaitor

This comment has been minimized.

ksaitor commented Jul 8, 2014

Thank you! 👍

@yairsz

This comment has been minimized.

yairsz commented Feb 25, 2015

Excelent! Thank you!

@vcostin

This comment has been minimized.

vcostin commented Jun 19, 2015

Thanks!

@ravinsinghd

This comment has been minimized.

ravinsinghd commented Jun 23, 2015

Thanks

@jhclaura

This comment has been minimized.

jhclaura commented Jul 19, 2015

Works great! Thank!

@mkpenrod05

This comment has been minimized.

mkpenrod05 commented Nov 7, 2015

Simple and sweet, thanks!

@alexmorleyfinch

This comment has been minimized.

alexmorleyfinch commented Nov 11, 2015

This is okay for generating less than 10 thousand unique IDs, but any more than 10 thousand and you are going to run into collisions.

I wrote a simple function to check for duplicates:

function checkDuplicates(generator, count){
  var hash = {};
  var dupe = [];
  for(var idx = 0; idx < count; ++idx){
    var gen = generator(idx); // generate our unique ID

    // if it already exists, then it has been duplicated
    if(typeof hash[gen] != 'undefined'){
      dupe.push({
        duplicate: gen,
        indexCreated: hash[gen],
        indexDuplicated: idx,
        duplicateCount: dupe.filter(function(cur){return cur.duplicate == gen}).length,
      });
    }
    hash[gen] = idx;
  }
  return dupe;
}

This function returns an array of duplicates. The format of a returned duplicate is as follows:

duplicate = {
  duplicate: "7srx2zt3zj2lnmi", // the generated id that was duplicated
  duplicateCount: 0,            // 0 is the first duplication, so 1 is the second duplication etc
  indexCreated: 133959,         // the index where the original ID was created
  indexDuplicated: 168948,      // the index where the original ID is duplicated
}

All you need to do is pass a function that returns your generated unique IDs, and the number of times you want to generate. The function is used like so:

function myUniqueID(){
  return Math.random().toString(36).slice(2);
}

checkDuplicates(myUniqueID, Math.pow(10, 4)); // Math.pow(10, 4) == 10'000 times

Calling the above returns an empty array. This means that no duplicates were found for less than 10 thousand iterations.

It you keep calling this, you keep getting 0 duplications. However, if you change the number of iterations to 100 thousand (or Math.pow(10, 5)), then you get between 0 and 3 duplicates. Change to 1 million and you get more than 100 duplicates. Change it to 10 million and you'll get thousands of duplicates.

Also, if you change it to 10 million you start to get multiple copies of duplicates! The same generated ID is not only duplicated once, but sometimes many times! If you run the following code, it will show you which keys were duplicated more than once (it may take a minute):

var duplicates = checkDuplicates(myUniqueID, Math.pow(10, 7)) // 10 MILLION

// now only show the duplicates that have a `duplicateCount` of more than 1
// (meaning they have been duplicated for a second time)
duplicates.filter(function(cur){
  return cur.duplicateCount > 0
});

When I run it with 10 million iterations, we get over 10 thousand duplicates, 10 of which have been duplicated twice

So as we can see, this function is okay for less than 10 thousand IDs, but any more and you are likely to run into collisions.

Therefore, do not use this to generate unique IDs. There are much better ways to do it.

However, a simple fix to get a lot less collisions would be to append the current time (new Date).getTime() to the returned ID. However, this still gets a few collisions when checking duplications for 10 million (still better than thousands)

Just out of interest, I found this function. It also uses Math.random, however it uses it multiple times, effectively reducing the chance that Math.random will generate the same numbers in the same order. It outputs a string in the format of a UUID (Universally Unique IDentifier).

function uniqueID(){
  function chr4(){
    return Math.random().toString(16).slice(-4);
  }
  return chr4() + chr4() +
    '-' + chr4() +
    '-' + chr4() +
    '-' + chr4() +
    '-' + chr4() + chr4() + chr4();
}

uniqueID() // "e27881c4-f924-b8f7-59d9-525878c7a812"

// NOTE: This format of 8 chars, followed by 3 groups of 4 chars, followed by 12 chars
//       is known as a UUID and is defined in RFC4122 and is a standard for generating unique IDs.
//       This function DOES NOT implement this standard. It simply outputs a string
//       that looks similar. The standard is found here: https://www.ietf.org/rfc/rfc4122.txt

If you call checkDuplicates with this, you will see that even with 10 million generations (or Math.pow(10, 7)) a collision is not detected, so this appears pretty safe.

I tried to run Math.pow(10, 8) which is 100 million, but it took forever and never finished. You may want to run your own tests for more than 100 million

@marcosschlup

This comment has been minimized.

marcosschlup commented Mar 3, 2016

For unique you can use Date.now() plus a random:

(Date.now().toString(36) + Math.random().toString(36).substr(2, 5)).toUpperCase()

@abdulhannanali

This comment has been minimized.

abdulhannanali commented Mar 4, 2016

@marcosschlup How are you sure it'll be a random unique id?

@huang-xiao-jian

This comment has been minimized.

huang-xiao-jian commented Apr 1, 2016

thanks, very helpful

@mniak

This comment has been minimized.

mniak commented Jun 22, 2016

Really good

@natsimhan

This comment has been minimized.

natsimhan commented Jul 1, 2016

Excellent solution alexmorleyfinch ;) And thx author for original id ;)

@iddan

This comment has been minimized.

iddan commented Jul 21, 2016

Using it all the time! thank you

@hegwin

This comment has been minimized.

hegwin commented Sep 20, 2016

So cool. Thanks.

@mzhda

This comment has been minimized.

mzhda commented Oct 15, 2016

this is helpful

@MichaelDimitras

This comment has been minimized.

MichaelDimitras commented Oct 18, 2016

Thanks a lot alexmorleyfinch. This was really informative.

@devboxr

This comment has been minimized.

devboxr commented Jun 16, 2017

I'm writing this in the hopes that others may find this on Google.

I had an issue that I'm using a v-for in Vue.js on a component, but in Vue 2.2+ you required :key to be set with a unique identifier. In my case the Array that it iterates over doesn't have any, so I had to generate one on demand (imagine a Bootstrap alerts manager component, e.g.). This will do just fine.

#vuejs #v-for

@hackeronline7

This comment has been minimized.

hackeronline7 commented Jun 25, 2017

Thanks!

@balaarunreddyv1

This comment has been minimized.

balaarunreddyv1 commented Jun 28, 2017

Thanks

@iatsiuk

This comment has been minimized.

iatsiuk commented Jul 25, 2017

@devboxr :key must be unique inside the v-for loop, not for the entire vue component. in your case array has an index and that is enough

@up209d

This comment has been minimized.

up209d commented Jul 26, 2017

I think the first one still the best, if you don't want it run into a collision just make one more

'-' + Math.random().toString(36).substr(2, 9) + '-' + Math.random().toString(36).substr(2, 9)

@beenotung

This comment has been minimized.

beenotung commented Aug 21, 2017

@devboxr iatsiuk's suggestion is more simple, for fun or other cases, you can get a unique id (without randomness) in a pretty effective way just by counting (Thanks to Javascript's single thread limitation).

You may take a reference on this demo:

export interface Counter {
  next(): number;
}

export function new_counter(init = 0): Counter {
  return {
    next: () => ++init
  };
}

export const Counter = new_counter(1);
@LindanTian

This comment has been minimized.

LindanTian commented Oct 16, 2017

cool

@huzemin

This comment has been minimized.

huzemin commented Oct 26, 2017

Thinks

@axd7832

This comment has been minimized.

axd7832 commented Nov 6, 2017

Simplicity is key. Thanks.

@n7best

This comment has been minimized.

n7best commented Nov 13, 2017

good stuff

@radius314

This comment has been minimized.

radius314 commented Nov 15, 2017

👍

@Jeslopov

This comment has been minimized.

Jeslopov commented Dec 14, 2017

Thanks

@FatemeNoruzi

This comment has been minimized.

FatemeNoruzi commented Dec 26, 2017

👍

@loyoliteabid

This comment has been minimized.

loyoliteabid commented Dec 29, 2017

Thanks

@geezywap

This comment has been minimized.

geezywap commented Jan 12, 2018

@ManGysT

This comment has been minimized.

ManGysT commented Jan 23, 2018

Thnaks man!

@mhcreative

This comment has been minimized.

mhcreative commented Jan 25, 2018

Thanks. Great, simple script.

@shradha03

This comment has been minimized.

shradha03 commented Feb 8, 2018

Thanks, it was of great help.

@lcherone

This comment has been minimized.

lcherone commented Feb 18, 2018

For any length IDs:

var ID = function (length) {
    if (!length) {
        length = 8
    }
    var str = ''
    for (var i = 1; i < length + 1; i = i + 8) {
        str += Math.random().toString(36).substr(2, 10)
    }
    return ('_' + str).substr(0, length)
}
@KalanaPerera

This comment has been minimized.

KalanaPerera commented Feb 22, 2018

Thanks!!

@lcherone

This comment has been minimized.

lcherone commented Feb 26, 2018

Another way which uses a cryptographically secure random number generator, in UUID format.

var ID = () => {
  let array = new Uint32Array(8)
  window.crypto.getRandomValues(array)
  let str = ''
  for (let i = 0; i < array.length; i++) {
    str += (i < 2 || i > 5 ? '' : '-') + array[i].toString(16).slice(-4)
  }
  return str
}
@proishan11

This comment has been minimized.

proishan11 commented Mar 13, 2018

Great! Can we write a unit test for this function? I am unable to figure out how to approach this. Thanks 😄

@JacksonElfers

This comment has been minimized.

JacksonElfers commented Mar 30, 2018

Generating unique id's is a bigger headache than I thought. If there's anything to study its how to do this correctly because I've seen plenty of implementations that claim to work but are then quickly discredited.

@Planeur

This comment has been minimized.

Planeur commented Apr 14, 2018

Math.random() is not unique. But time stamp generated ids could be.

@Planeur

This comment has been minimized.

Planeur commented Apr 14, 2018

a simple way to do this:

(new Date().getTime()).toString(36)

@williamyeny

This comment has been minimized.

williamyeny commented Apr 28, 2018

@Planeur Timestamp IDs are technically not unique because you could have the same ID if the IDs are generated within the same millisecond. Try combining timestamp and Math.random to make it even more unlikely for collisions

var ID = Date.now() + Math.random().toString().slice(2);

@krisan012

This comment has been minimized.

krisan012 commented May 7, 2018

awesome thanks :D

@jorhel

This comment has been minimized.

jorhel commented Jun 13, 2018

Thankyou from the help.
My code:

function genID(){
    this.inner = [];
    this.unique = function( id ){
        for( var actID in this.inner ){
           if( actID === this.inner ){
                break;
               return false;
           }
        }
        return id;
    };
    this.gen = function( len ){
        len = typeof len !== "number" ? 36 : len;
        let id = false;
        while( !id ){
            id = this.unique('_' + (Date.now().toString( len ) + Math.random().toString( len ).substr(2, 5)).toUpperCase());
        }
         this.inner.push( id );
        console.log( this.inner );
        return id;
    };
    return this;
}

Use:

var foo = new genID();
console.log( foo.gen() );
console.log( foo.gen() );

@yukulele

This comment has been minimized.

yukulele commented Jul 18, 2018

Math.round((Math.random() * 36 ** 12)).toString(36);
// "u8dbda25zwik"
@Saifeddine-Rjab

This comment has been minimized.

Saifeddine-Rjab commented Sep 1, 2018

Thanks this is very helpful

@robsongajunior

This comment has been minimized.

robsongajunior commented Sep 19, 2018

random and timestamp based at milions request maybe it is not unic...
.. should be implemented using RFC4122

Using JavaScript the correct way it is using UUID4, based in random.
uuid-v4.js

@Horse303

This comment has been minimized.

Horse303 commented Sep 20, 2018

Hello. Thank you for posting this.
I did some testing to see how often collisions will occur (because for my nodejs RPG game, low length id is required and well, have as less collisions as possible).
I was very surprised with results.
(HashMap is my container, written in typescript)

I am failing to force this stupid post GUI to style the code. Therefore: code starts here:

`
results:
//stats results:
//1000 ids generated: 0 collisions
//10000 ids generated: 0 collisions
//100000 ids generated: 0 collisions
//1 milion ids generated: 0 collisions
//10 milion ids generated: 0 collisions

it('Collision finding', (done) => {
var hm = new HashMap<string, number>();
var iterations = 10000000;
var collisionsFound = 0;
for (let i = 0; i < iterations; i++) {
var id = Math.random().toString(36).substr(2, 9);
while (hm.contains(id)) {
console.log('id ${id} collision');
id = Math.random().toString(36).substr(2, 9);
collisionsFound++;
}
hm.insert(id, 2);
}
console.log('had ${collisionsFound} collisions in ${iterations} iterations');
});`

@Tusbahle

This comment has been minimized.

Tusbahle commented Oct 17, 2018

thanks !, it helped me....

@igorrybalko

This comment has been minimized.

igorrybalko commented Oct 23, 2018

Thanks, great solution.

@lmj0011

This comment has been minimized.

lmj0011 commented Nov 8, 2018

For anonymous analytic collecting from a pool of 10's of thousands of active users, maybe 100's, OP's solution should be fine to use.

However, I decided to tinker with my own implementation and came up with this (piggybacking off of @Planeur):

'_' + (new Date().getUTCMilliseconds().toString() + new Date().getTime().toString()).toString();

// "_4511541719590451"

not sure the base it would take to convert this into an alphanumerical string

@zhiwenjunjin

This comment has been minimized.

zhiwenjunjin commented Nov 12, 2018

when you pick the substring, how can you be sure it is still unique?

@neyron163

This comment has been minimized.

neyron163 commented Nov 21, 2018

Thanks

@jaitheking

This comment has been minimized.

jaitheking commented Dec 10, 2018

Thank you. This is simple and easy to use

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment