Create a gist now

Instantly share code, notes, and snippets.

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);
};

Thank you, it was helpful :)

Thanks, working great. :)

Thank you.

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 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).

Thanks!

ksaitor commented Jul 8, 2014

Thank you! 👍

yairsz commented Feb 25, 2015

Excelent! Thank you!

vcostin commented Jun 19, 2015

Thanks!

Thanks

Works great! Thank!

Simple and sweet, thanks!

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

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

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

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

thanks, very helpful

mniak commented Jun 22, 2016

Really good

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

iddan commented Jul 21, 2016

Using it all the time! thank you

hegwin commented Sep 20, 2016

So cool. Thanks.

mzhda commented Oct 15, 2016

this is helpful

MichaelDimitras commented Oct 18, 2016

Thanks a lot alexmorleyfinch. This was really informative.

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

Thanks!

Thanks

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 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 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);

cool

huzemin commented Oct 26, 2017

Thinks

axd7832 commented Nov 6, 2017

Simplicity is key. Thanks.

n7best commented Nov 13, 2017

good stuff

👍

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