Come creare GUID / UUID?


4180

Sto cercando di creare identificatori univoci a livello globale in JavaScript. Non sono sicuro di quali routine siano disponibili su tutti i browser, quanto sia "casuale" e seminato il generatore di numeri casuali incorporato, ecc.

Il GUID / UUID deve contenere almeno 32 caratteri e deve rimanere nell'intervallo ASCII per evitare problemi durante il passaggio.


13
I GUID se rappresentati come stringhe hanno almeno 36 e non più di 38 caratteri di lunghezza e corrispondono al modello ^ \ {? [A-zA-Z0-9] {36}? \} $ E quindi sono sempre ascii.
AnthonyWJones,

2
David Bau fornisce un generatore di numeri casuali molto migliore e seminabile su davidbau.com/archives/2010/01/30/… Ho scritto un approccio leggermente diverso alla generazione di UUID su blogs.cozi.com/tech/2010/04/generating- uuids-in-javascript.html
George V. Reilly,

Strano che nessuno lo abbia ancora menzionato, ma per completezza, c'è una pletora di generatori di guid su npm Sono disposto a scommettere che molti di loro funzionano anche nel browser.
George Mauer,

Risposte:


2339

Gli UUID (IDentificatore univoco universale), noti anche come GUID (IDentificatore univoco globale), secondo RFC 4122 , sono identificatori progettati per fornire determinate garanzie di unicità.

Mentre è possibile implementare un UUID conforme a RFC in alcune righe di JS (ad esempio vedi la risposta di @ broofa , di seguito) ci sono molte insidie ​​comuni:

  • Formato ID non valido (gli UUID devono essere nel formato " xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx", dove x è uno di [0-9, af] M è uno di [1-5] e N è [8, 9, a o b]
  • Uso di una fonte di casualità di bassa qualità (come Math.random)

Pertanto, gli sviluppatori che scrivono codice per ambienti di produzione sono incoraggiati a utilizzare un'implementazione rigorosa e ben mantenuta come il modulo uuid .


186
In realtà, l'RFC consente UUID creati da numeri casuali. Devi solo modificare un paio di bit per identificarlo come tale. Vedere la sezione 4.4. Algoritmi per la creazione di un UUID da numeri veramente casuali o pseudo-casuali: rfc-archive.org/getrfc.php?rfc=4122
Jason DeFontes,

Basandomi su tutto in questo thread, ho creato una versione due volte più veloce della variante "e7" di seguito, cripto-forte, e funziona su tutti i principali browser e nodi. È troppo grande per includerlo qui, quindi cerca una nuova risposta con il mio nome il 17 maggio 2020.
Bennett Barouch

node-uuid ora è diventato uuid (dopo essersi unito a quest'ultimo progetto)
Catweazle

4116

Per una soluzione conforme alla versione 4 di RFC4122 , questa soluzione one-liner (ish) è la più compatta che potrei trovare:

function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

console.log(uuidv4());

Aggiornamento, 02/06/2015 : tenere presente che l'unicità UUID si basa fortemente sul generatore di numeri casuali sottostante (RNG). La soluzione di cui sopra utilizza Math.random()per brevità, tuttavia nonMath.random() è garantito per essere un RNG di alta qualità. Vedi l' eccellente write-up di Adam Hyland su Math.random () per i dettagli. Per una soluzione più solida, considera l'utilizzo del modulo uuid , che utilizza API RNG di qualità superiore.

Aggiornamento, 26-08-2015 : come nota a margine , questa sintesi descrive come determinare quanti ID possono essere generati prima di raggiungere una certa probabilità di collisione. Ad esempio, con UUID RFC4122 versione 4 3.26x10 15 hai una probabilità di collisione di 1 su un milione.

Aggiornamento, 28/06/2017 : un buon articolo degli sviluppatori di Chrome che parla dello stato della qualità PRNG di Math.random in Chrome, Firefox e Safari. tl; dr - Alla fine del 2015 è "abbastanza buono", ma non di qualità crittografica. Per risolvere il problema, ecco una versione aggiornata della soluzione di cui sopra che utilizza ES6, l' cryptoAPI e un po 'di procedura guidata JS di cui non posso prendere in considerazione :

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  );
}

console.log(uuidv4());

Aggiornamento, 2020-01-06 : è in corso una proposta per un uuidmodulo standard come parte del linguaggio JS


30
Ho postato una domanda sul collisioni stackoverflow.com/questions/6906916/...
Muxa

4
@marc - La qualità di Math.random () è una preoccupazione. Ma senza un'analisi dettagliata dell'implementazione sottostante, che varia quasi sicuramente x-browser, non possiamo conoscere le effettive probabilità di collisione. Quindi per semplicità sto assumendo una fonte ideale di casualità. Ma sì, può essere un presupposto pericoloso come evidenzia il problema di Muxa. È anche il motivo per cui in node-uuid ( github.com/broofa/node-uuid ) preferisco altre API che garantiscono casualità di qualità crittografica rispetto a Math.random (), anche se le prestazioni ne soffrono.
broofa,

144
Sicuramente la risposta alla domanda di @ Muxa è "no"? Non è mai veramente sicuro fidarsi di qualcosa che proviene dal cliente. Immagino che dipenda dalla probabilità con cui i tuoi utenti aprono una console javascript e cambiano manualmente la variabile in base a qualcosa che desiderano. Oppure potrebbero semplicemente postarti l'id che vogliono. Dipenderebbe anche se l'utente che seleziona il proprio ID causerà vulnerabilità. In entrambi i casi, se si tratta di un ID di numero casuale inserito in una tabella, probabilmente lo genererei sul lato server, in modo da sapere di avere il controllo del processo.
Cam Jackson

36
@DrewNoakes - Gli UUID non sono solo una serie di # completamente casuali. "4" è la versione uuid (4 = "random"). La "y" indica dove deve essere incorporata la variante uuid (layout del campo). Vedere le sezioni 4.1.1 e 4.1.3 di ietf.org/rfc/rfc4122.txt per maggiori informazioni.
broofa,

5
perché c== 'x'invece di c === 'x'. Perché jshint non è riuscito.
Fizer Khan,

811

Mi piace davvero quanto sia chiara la risposta di Broofa , ma è un peccato che cattive implementazioniMath.random lascino la possibilità di una collisione.

Ecco una simile soluzione RFC4122 versione 4 conforme che risolve il problema compensando i primi 13 numeri esadecimali di una porzione esadecimale del timestamp e una volta esauriti gli offset di una porzione esadecimale dei microsecondi dal pageload. In questo modo, anche se si Math.randomtrova sullo stesso seed, entrambi i client dovrebbero generare l'UUID lo stesso numero esatto di microsecondi dal pageload (se è supportato un tempo ad alte prestazioni) E allo stesso millisecondo esatto (o oltre 10.000 anni dopo) per ottieni lo stesso UUID:

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();//Timestamp
    var d2 = (performance && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16;//random number between 0 and 16
        if(d > 0){//Use timestamp until depleted
            r = (d + r)%16 | 0;
            d = Math.floor(d/16);
        } else {//Use microseconds since page-load if supported
            r = (d2 + r)%16 | 0;
            d2 = Math.floor(d2/16);
        }
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}

console.log(generateUUID())


Ecco un violino da testare.


31
Ricorda, new Date().getTime()non viene aggiornato ogni millisecondo. Non sono sicuro di come ciò influisca sulla casualità attesa del tuo algoritmo.
devios1

84
performance.now sarebbe ancora meglio. A differenza di Date.now, i timestamp restituiti da performance.now()non si limitano alla risoluzione di un millisecondo. Al contrario, rappresentano i tempi come numeri a virgola mobile con precisione fino al microsecondo . Inoltre, diversamente da Date.now, i valori restituiti da performance.now () aumentano sempre a una velocità costante , indipendentemente dall'orologio di sistema che potrebbe essere regolato manualmente o distorto da software come Network Time Protocol.
daniellmb,

6
@daniellmb Probabilmente avresti dovuto collegarti a MDN o altro per mostrare la vera documentazione e non un polyfill;)
Martin

2
Posso sapere a cosa serve l'arrotondamento d = Math.floor(d/16);?
Praveen,

2
@Praveen Quell'operazione sposta il timestamp di una cifra esadecimale verso destra e rilascia il resto. Il suo scopo è quello di sbarazzarsi della cifra esadecimale che abbiamo appena usato (la meno significativa) e prepararla per la prossima iterazione.
Briguy37,

431

la risposta di broofa è piuttosto semplice, davvero - straordinariamente intelligente, davvero ... conforme a rfc4122, in qualche modo leggibile e compatta. Eccezionale!

Ma se stai guardando quell'espressione regolare, quei tanti replace()callback, toString()e le Math.random()chiamate di funzione (dove sta usando solo 4 bit del risultato e sprecando il resto), potresti iniziare a chiederti delle prestazioni. In effetti, Joelpt ha persino deciso di lanciare RFC per la velocità GUID generica con generateQuickGUID.

Ma possiamo ottenere velocità e conformità RFC? Io dico si! Possiamo mantenere la leggibilità? Beh ... Non proprio, ma è facile se lo segui.

Ma prima, i miei risultati, rispetto a broofa, guid(la risposta accettata), e non conformi a rfc generateQuickGuid:

                  Desktop   Android
           broofa: 1617ms   12869ms
               e1:  636ms    5778ms
               e2:  606ms    4754ms
               e3:  364ms    3003ms
               e4:  329ms    2015ms
               e5:  147ms    1156ms
               e6:  146ms    1035ms
               e7:  105ms     726ms
             guid:  962ms   10762ms
generateQuickGuid:  292ms    2961ms
  - Note: 500k iterations, results will vary by browser/cpu.

Quindi, con la mia sesta iterazione di ottimizzazioni, ho battuto la risposta più popolare di oltre 12X , la risposta accettata di oltre 9X e la risposta rapida e non conforme di 2-3X . E sono ancora conforme a rfc4122.

Interessato a come? Ho messo la fonte completa su http://jsfiddle.net/jcward/7hyaC/3/ e su http://jsperf.com/uuid-generator-opt/4

Per una spiegazione, iniziamo con il codice di broofa:

function broofa() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

console.log(broofa())

Quindi sostituisce xcon qualsiasi cifra esadecimale casuale, ycon dati casuali (tranne forzando i primi 2 bit 10secondo le specifiche RFC), e il regex non corrisponde ai caratteri -o 4, quindi non deve affrontarli. Molto, molto lucido.

La prima cosa da sapere è che le chiamate di funzione sono costose, così come le espressioni regolari (sebbene usi solo 1, ha 32 callback, una per ogni corrispondenza, e in ognuna delle 32 callback chiama Math.random () e v. toString (16)).

Il primo passo verso le prestazioni è eliminare RegEx e le sue funzioni di callback e utilizzare invece un semplice loop. Questo significa che dobbiamo fare i conti con i personaggi -e 4mentre Broofa no. Inoltre, tieni presente che possiamo utilizzare l'indicizzazione String Array per mantenere la sua elegante architettura del modello String:

function e1() {
    var u='',i=0;
    while(i++<36) {
        var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:v.toString(16)
    }
    return u;
}

console.log(e1())

Fondamentalmente, la stessa logica interna, tranne che controlliamo -o 4, e usando un ciclo while (invece di replace()callbacks) ci dà un miglioramento quasi 3X!

Il passo successivo è piccolo sul desktop ma fa una discreta differenza sui dispositivi mobili. Facciamo meno chiamate Math.random () e utilizziamo tutti quei bit casuali invece di buttarne via l'87% con un buffer casuale che viene spostato fuori da ogni iterazione. Spostiamo anche quella definizione del modello fuori dal ciclo, nel caso in cui aiuti:

function e2() {
    var u='',m='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<36) {
        var c=m[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:v.toString(16);rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
    }
    return u
}

console.log(e2())

Questo ci consente di risparmiare il 10-30% a seconda della piattaforma. Non male. Ma il prossimo grande passo si sbarazza delle chiamate alla funzione toString con un classico di ottimizzazione: la tabella di ricerca. Una semplice tabella di ricerca a 16 elementi eseguirà il lavoro di toString (16) in molto meno tempo:

function e3() {
    var h='0123456789abcdef';
    var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
    /* same as e4() below */
}
function e4() {
    var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
    var k=['x','x','x','x','x','x','x','x','-','x','x','x','x','-','4','x','x','x','-','y','x','x','x','-','x','x','x','x','x','x','x','x','x','x','x','x'];
    var u='',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<36) {
        var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
    }
    return u
}

console.log(e4())

La prossima ottimizzazione è un altro classico. Dato che gestiamo solo 4 bit di output in ogni iterazione di loop, riduciamo il numero di loop a metà ed elaboriamo 8 bit per ogni iterazione. Questo è difficile poiché dobbiamo ancora gestire le posizioni dei bit conformi a RFC, ma non è troppo difficile. Dobbiamo quindi creare una tabella di ricerca più grande (16x16 o 256) per memorizzare 0x00 - 0xff e la costruiamo una sola volta, al di fuori della funzione e5 ().

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e5() {
    var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];
    var u='',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<20) {
        var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));
        u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8
    }
    return u
}

console.log(e5())

Ho provato un e6 () che elabora 16 bit alla volta, usando ancora il LUT a 256 elementi e ha mostrato i rendimenti decrescenti dell'ottimizzazione. Sebbene avesse meno iterazioni, la logica interna era complicata dall'aumento dell'elaborazione e ha funzionato allo stesso modo sul desktop e solo del 10% più veloce sui dispositivi mobili.

La tecnica di ottimizzazione finale da applicare: srotolare il loop. Dato che eseguiamo il looping di un numero fisso di volte, possiamo tecnicamente scrivere tutto questo a mano. Ci ho provato una volta con una singola variabile casuale r che ho continuato a riassegnare e le prestazioni sono aumentate. Ma con quattro variabili assegnate in anticipo dati casuali, quindi utilizzando la tabella di ricerca e applicando i bit RFC corretti, questa versione li fuma tutti:

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e7()
{
    var d0 = Math.random()*0xffffffff|0;
    var d1 = Math.random()*0xffffffff|0;
    var d2 = Math.random()*0xffffffff|0;
    var d3 = Math.random()*0xffffffff|0;
    return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
    lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
    lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
    lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
}

console.log(e7())

Modificato: http://jcward.com/UUID.js -UUID.generate()

La cosa divertente è che generare 16 byte di dati casuali è la parte facile. L'intero trucco è esprimerlo in formato String con conformità RFC ed è realizzato in modo molto preciso con 16 byte di dati casuali, un ciclo non srotolato e una tabella di ricerca.

Spero che la mia logica sia corretta - è molto facile commettere un errore in questo tipo di noioso bit-lavoro. Ma le uscite sembrano buone per me. Spero che ti sia piaciuta questa folle corsa attraverso l'ottimizzazione del codice!

Attenzione: il mio obiettivo principale era mostrare e insegnare le potenziali strategie di ottimizzazione. Altre risposte riguardano argomenti importanti come collisioni e numeri veramente casuali, che sono importanti per generare buoni UUID.


14
Questo codice contiene ancora un paio di errori: le Math.random()*0xFFFFFFFFrighe dovrebbero essere Math.random()*0x100000000completamente casuali e >>>0dovrebbero essere usate invece di |0mantenere i valori non firmati (anche se con il codice corrente penso che vada via OK anche se sono firmati). Alla fine sarebbe una buona idea in questi giorni usare window.crypto.getRandomValuesse disponibile e ricorrere a Math.random solo se assolutamente necessario. Math.random potrebbe avere meno di 128 bit di entropia, nel qual caso questo sarebbe più vulnerabile alle collisioni del necessario.
Dave,

Basandomi su tutto già su questo thread, ho creato qualcosa due volte più veloce di "e7", portatile tutti gli ambienti, incluso il nodo, e aggiornato da Math.random () alla casualità criptata. Potresti non pensare che il uuid abbia bisogno di forza cripto, ma ciò significa anche meno possibilità di una collisione, che è l'intero punto di un uuid. Troppo grande per essere inserito in un commento, l'ho pubblicato separatamente.
Bennett Barouch,

164

Ecco del codice basato su RFC 4122 , sezione 4.4 (Algoritmi per la creazione di un UUID da un numero veramente casuale o pseudo-casuale).

function createUUID() {
    // http://www.ietf.org/rfc/rfc4122.txt
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

    var uuid = s.join("");
    return uuid;
}

4
È necessario dichiarare in anticipo la dimensione della matrice anziché ridimensionarla dinamicamente durante la creazione del GUID. var s = new Array(36);
MgSam

1
Penso che ci sia un bug molto piccolo nella riga che imposta i bit 6-7 di clock_seq_hi_and_reserved su 01. Poiché s [19] è un carattere '0' .. 'f' e non un int 0x0..0xf, (s [19] e 0x3) | 0x8 non verrà distribuito casualmente - tenderà a produrre più '9 e meno' b. Questo fa la differenza solo se ti preoccupi della distribuzione casuale per qualche motivo.
John Velonis,

153
let uniqueId = Math.random().toString(36).substring(2) + Date.now().toString(36);

Se gli ID vengono generati a più di 1 millisecondo di distanza, sono unici al 100%.

Se due ID vengono generati a intervalli più brevi e supponendo che il metodo casuale sia veramente casuale, ciò genererebbe ID con una probabilità del 99.999999999999999999% di essere univoci a livello globale (collisione in 1 di 10 ^ 15)

Puoi aumentare questo numero aggiungendo più cifre, ma per generare ID univoci al 100% dovrai utilizzare un contatore globale.

se è necessaria la compatibilità RFC, questa formattazione passerà come GUID versione 4 valido:

let u = Date.now().toString(16) + Math.random().toString(16) + '0'.repeat(16);
let guid = [u.substr(0,8), u.substr(8,4), '4000-8' + u.substr(13,3), u.substr(16,12)].join('-');

Modifica: il codice sopra riportato segue l'intenzione, ma non la lettera della RFC. Tra le altre discrepanze, alcune cifre casuali sono brevi. (Aggiungi più cifre casuali se ne hai bisogno) Il lato positivo è che questo è davvero veloce :) Puoi testare la validità del tuo GUID qui


4
Questo non è UUID però?
Marco Kerwitz,

No. UUID / GUID è un numero di 122 bit (+ sei bit riservati). potrebbe garantire unicità attraverso un servizio di conteggio globale, ma spesso si basa su tempo, indirizzo MAC e casualità. Gli UUID non sono casuali! L'UID che suggerisco qui non è completamente compresso. È possibile comprimerlo, a un numero intero a 122 bit, aggiungere i 6 bit predefiniti e i bit extra casuali (rimuovere alcuni bit del timer) e si finisce con un UUID / GUID perfettamente formato, che si dovrebbe quindi convertire in esadecimale. Per me ciò non aggiunge altro che la conformità alla lunghezza dell'ID.
Simon Rigét,

5
Inoltro su indirizzi MAC per unicità su macchine virtuali è una cattiva idea!
Simon Rigét,

1
Faccio qualcosa del genere, ma con personaggi principali e alcuni trattini (ad es. [slug, date, random].join("_")Per creare usr_1dcn27itd_hj6onj6phr. Lo rende così l'ID funge anche da campo "creato a"
Seph Reed,

95

Il GUID più veloce come il metodo generatore di stringhe nel formato XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Questo non genera GUID conforme allo standard.

Dieci milioni di esecuzioni di questa implementazione richiedono solo 32,5 secondi, che è la più veloce che abbia mai visto in un browser (l'unica soluzione senza loop / iterazioni).

La funzione è semplice come:

/**
 * Generates a GUID string.
 * @returns {string} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser.
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

Per testare le prestazioni, è possibile eseguire questo codice:

console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    guid(); 
};
console.timeEnd('t');

Sono sicuro che molti di voi capiranno quello che ho fatto lì, ma forse c'è almeno una persona che avrà bisogno di una spiegazione:

L'algoritmo:

  • La Math.random()funzione restituisce un numero decimale compreso tra 0 e 1 con 16 cifre dopo il punto decimale della frazione (ad esempio0.4363923368509859 ).
  • Quindi prendiamo questo numero e lo convertiamo in una stringa con base 16 (dall'esempio sopra otterremo 0.6fb7687f).
    Math.random().toString(16).
  • Quindi tagliamo il 0.prefisso ( 0.6fb7687f=> 6fb7687f) e otteniamo una stringa con otto caratteri esadecimali lunghi.
    (Math.random().toString(16).substr(2,8).
  • A volte la Math.random()funzione restituisce un numero più breve (ad esempio 0.4363), a causa degli zeri alla fine (dall'esempio sopra, in realtà il numero è 0.4363000000000000). Ecco perché sto aggiungendo questa stringa "000000000"(una stringa con nove zeri) e quindi tagliandola con la substr()funzione per renderla esattamente di nove caratteri (riempiendo gli zeri a destra).
  • Il motivo per aggiungere esattamente nove zeri è a causa dello scenario peggiore, ovvero quando la Math.random()funzione restituirà esattamente 0 o 1 (probabilità di 1/10 ^ 16 per ciascuno di essi). Ecco perché dovevamo aggiungere nove zeri ( "0"+"000000000"o "1"+"000000000") e quindi tagliarlo dal secondo indice (3 ° carattere) con una lunghezza di otto caratteri. Per il resto dei casi, l'aggiunta di zeri non danneggerà il risultato perché lo sta comunque tagliando.
    Math.random().toString(16)+"000000000").substr(2,8).

L'assemblea:

  • Il GUID è nel seguente formato XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • Ho diviso il GUID in 4 pezzi, ogni pezzo diviso in 2 tipi (o formati): XXXXXXXXe -XXXX-XXXX.
  • Ora sto costruendo il GUID utilizzando questi 2 tipi di assemblare il GUID con la chiamata di 4 pezzi, come segue: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • A differenza di questi due tipi, ho aggiunto un parametro flag a una funzione creatore di coppia _p8(s), il sparametro dice alla funzione se aggiungere trattini o meno.
  • Alla fine costruiamo il GUID con il seguente concatenamento: _p8() + _p8(true) + _p8(true) + _p8()e lo restituiamo.

Link a questo post sul mio blog

Godere! :-)


13
Questa implementazione non è corretta. Alcuni caratteri del GUID richiedono un trattamento speciale (ad es. La 13a cifra deve essere il numero 4).
JLRè il

67

Ecco una combinazione della risposta più votata , con una soluzione alternativa per le collisioni di Chrome :

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // /programming/6906916/collisions-when-generating-uuids-in-javascript
        var buf = new Uint16Array(8);
        window.crypto.getRandomValues(buf);
        var S4 = function(num) {
            var ret = num.toString(16);
            while(ret.length < 4){
                ret = "0"+ret;
            }
            return ret;
        };
        return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
    }

    :

    function() {
        // Otherwise, just use Math.random
        // /programming/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
            return v.toString(16);
        });
    };

Su jsbin se vuoi testarlo.


3
nota che la prima versione, quella `window.crypto.getRandomValues , does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` produce xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
umanità e

66

Ecco un'implementazione totalmente non conforme ma molto performante per generare un identificatore univoco simile a GUID ASCII-sicuro.

function generateQuickGuid() {
    return Math.random().toString(36).substring(2, 15) +
        Math.random().toString(36).substring(2, 15);
}

Genera 26 [a-z0-9] caratteri, producendo un UID più corto e più unico dei GUID conformi a RFC. I trattini possono essere aggiunti banalmente se la leggibilità umana è importante.

Ecco alcuni esempi di utilizzo e tempi per questa funzione e molte altre risposte a questa domanda. I tempi sono stati eseguiti con Chrome m25, 10 milioni di iterazioni ciascuno.

>>> generateQuickGuid()
"nvcjf1hs7tf8yyk4lmlijqkuo9"
"yq6gipxqta4kui8z05tgh9qeel"
"36dh5sec7zdj90sk2rx7pjswi2"
runtime: 32.5s

>>> GUID() // John Millikin
"7a342ca2-e79f-528e-6302-8f901b0b6888"
runtime: 57.8s

>>> regexGuid() // broofa
"396e0c46-09e4-4b19-97db-bd423774a4b3"
runtime: 91.2s

>>> createUUID() // Kevin Hakanson
"403aa1ab-9f70-44ec-bc08-5d5ac56bd8a5"
runtime: 65.9s

>>> UUIDv4() // Jed Schmidt
"f4d7d31f-fa83-431a-b30c-3e6cc37cc6ee"
runtime: 282.4s

>>> Math.uuid() // broofa
"5BD52F55-E68F-40FC-93C2-90EE069CE545"
runtime: 225.8s

>>> Math.uuidFast() // broofa
"6CB97A68-23A2-473E-B75B-11263781BBE6"
runtime: 92.0s

>>> Math.uuidCompact() // broofa
"3d7b7a06-0a67-4b67-825c-e5c43ff8c1e8"
runtime: 229.0s

>>> bitwiseGUID() // jablko
"baeaa2f-7587-4ff1-af23-eeab3e92"
runtime: 79.6s

>>>> betterWayGUID() // Andrea Turri
"383585b0-9753-498d-99c3-416582e9662c"
runtime: 60.0s

>>>> UUID() // John Fowler
"855f997b-4369-4cdb-b7c9-7142ceaf39e8"
runtime: 62.2s

Ecco il codice di temporizzazione.

var r;
console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    r = FuncToTest(); 
};
console.timeEnd('t');

62

Ecco una soluzione datata 9 ottobre 2011 da un commento dell'utente jed su https://gist.github.com/982883 :

UUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

Ciò raggiunge lo stesso obiettivo dell'attuale risposta con il punteggio più alto , ma in oltre 50 byte in meno sfruttando la coercizione, la ricorsione e la notazione esponenziale. Per i curiosi su come funziona, ecco la forma annotata di una versione precedente della funzione:

UUIDv4 =

function b(
  a // placeholder
){
  return a // if the placeholder was passed, return
    ? ( // a random number from 0 to 15
      a ^ // unless b is 8,
      Math.random() // in which case
      * 16 // a random number from
      >> a/4 // 8 to 11
      ).toString(16) // in hexadecimal
    : ( // or otherwise a concatenated string:
      [1e7] + // 10000000 +
      -1e3 + // -1000 +
      -4e3 + // -4000 +
      -8e3 + // -80000000 +
      -1e11 // -100000000000,
      ).replace( // replacing
        /[018]/g, // zeroes, ones, and eights with
        b // random hex digits
      )
}

52

Dal blog tecnico di sagi shkedy :

function generateGuid() {
  var result, i, j;
  result = '';
  for(j=0; j<32; j++) {
    if( j == 8 || j == 12 || j == 16 || j == 20) 
      result = result + '-';
    i = Math.floor(Math.random()*16).toString(16).toUpperCase();
    result = result + i;
  }
  return result;
}

Esistono altri metodi che prevedono l'utilizzo di un controllo ActiveX, ma state alla larga da questi!

Modifica: ho pensato che valesse la pena sottolineare che nessun generatore GUID può garantire chiavi univoche (consulta l' articolo di Wikipedia ). C'è sempre la possibilità di collisioni. Un GUID offre semplicemente un universo di chiavi abbastanza grande da ridurre quasi a zero il cambiamento delle collisioni.


8
Si noti che questo non è un GUID in senso tecnico, perché non fa nulla per garantire l'unicità. Ciò può o non può importare a seconda dell'applicazione.
Stephen Deken,

2
Una breve nota sulle prestazioni. Questa soluzione crea 36 stringhe in totale per ottenere un singolo risultato. Se le prestazioni sono fondamentali, prendere in considerazione la creazione di un array e l'unione come raccomandato da: tinyurl.com/y37xtx Ulteriori ricerche indicano che potrebbe non avere importanza, quindi YMMV: tinyurl.com/3l7945
Brandon DuRette,

2
Per quanto riguarda l'unicità, vale la pena notare che la versione 1,3 e 5 UUID sono deterministici come la versione 4 non lo è. Se gli input per questi generatori uuid - id nodo in v1, spazio dei nomi e nome in v3 e v5 - sono unici (come dovrebbero essere), gli UUID risultanti saranno univoci. In teoria, comunque.
broofa,

41

Puoi usare node-uuid ( https://github.com/kelektiv/node-uuid )

Generazione semplice e veloce di UUID RFC4122.

Caratteristiche:

  • Genera UUID RFC4122 versione 1 o versione 4
  • Funziona in node.js e browser.
  • # Generazione casuale casuale crittograficamente su piattaforme di supporto.
  • Ingombro ridotto (vuoi qualcosa di più piccolo? Dai un'occhiata! )

Installa utilizzando NPM:

npm install uuid

O usando uuid tramite browser:

Scarica il Raw File (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Scarica il Raw File (uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid / Master / v4.js


Vuoi ancora più piccolo? Dai un'occhiata a: https://gist.github.com/jed/982883


Uso:

// Generate a v1 UUID (time-based)
const uuidV1 = require('uuid/v1');
uuidV1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 UUID (random)
const uuidV4 = require('uuid/v4');
uuidV4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

// Generate a v5 UUID (namespace)
const uuidV5 = require('uuid/v5');

// ... using predefined DNS namespace (for domain names)
uuidV5('hello.example.com', v5.DNS)); // -> 'fdda765f-fc57-5604-a269-52a7df8164ec'

// ... using predefined URL namespace (for, well, URLs)
uuidV5('http://example.com/hello', v5.URL); // -> '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'

// ... using a custom namespace
const MY_NAMESPACE = '(previously generated unique uuid string)';
uuidV5('hello', MY_NAMESPACE); // -> '90123e1c-7512-523e-bb28-76fab9f2f73d'

ES6:

import uuid from 'uuid/v4';
const id = uuid();

34
var uuid = function() {
    var buf = new Uint32Array(4);
    window.crypto.getRandomValues(buf);
    var idx = -1;
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        idx++;
        var r = (buf[idx>>3] >> ((idx%8)*4))&15;
        var v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
};

MODIFICARE:

Rivisitato il mio progetto che utilizzava questa funzione e non mi piaceva la verbosità. - Ma avevo bisogno di una casualità adeguata.

Una versione basata sulla risposta di Briguy37 e alcuni operatori bit a bit per estrarre dal buffer finestre di dimensioni nibble.

Dovrebbe aderire allo schema RFC di tipo 4 (casuale), poiché l'ultima volta ho avuto problemi durante l'analisi degli uuidi non conformi con l'UUID di Java.


31

Modulo JavaScript semplice come combinazione delle migliori risposte in questo thread.

var crypto = window.crypto || window.msCrypto || null; // IE11 fix

var Guid = Guid || (function() {

  var EMPTY = '00000000-0000-0000-0000-000000000000';

  var _padLeft = function(paddingString, width, replacementChar) {
    return paddingString.length >= width ? paddingString : _padLeft(replacementChar + paddingString, width, replacementChar || ' ');
  };

  var _s4 = function(number) {
    var hexadecimalResult = number.toString(16);
    return _padLeft(hexadecimalResult, 4, '0');
  };

  var _cryptoGuid = function() {
    var buffer = new window.Uint16Array(8);
    window.crypto.getRandomValues(buffer);
    return [_s4(buffer[0]) + _s4(buffer[1]), _s4(buffer[2]), _s4(buffer[3]), _s4(buffer[4]), _s4(buffer[5]) + _s4(buffer[6]) + _s4(buffer[7])].join('-');
  };

  var _guid = function() {
    var currentDateMilliseconds = new Date().getTime();
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(currentChar) {
      var randomChar = (currentDateMilliseconds + Math.random() * 16) % 16 | 0;
      currentDateMilliseconds = Math.floor(currentDateMilliseconds / 16);
      return (currentChar === 'x' ? randomChar : (randomChar & 0x7 | 0x8)).toString(16);
    });
  };

  var create = function() {
    var hasCrypto = crypto != 'undefined' && crypto !== null,
      hasRandomValues = typeof(window.crypto.getRandomValues) != 'undefined';
    return (hasCrypto && hasRandomValues) ? _cryptoGuid() : _guid();
  };

  return {
    newGuid: create,
    empty: EMPTY
  };
})();

// DEMO: Create and show GUID
console.log(Guid.newGuid());

Uso:

Guid.newGuid ()

"C6c2d12f-d76b-5739-e551-07e6de5b0807"

Guid.empty

"00000000-0000-0000-0000-000000000000"


1
Ciò che preoccupa tutte le risposte è che sembra giusto che JavaScript memorizzi GUIDcome string. La tua risposta affronta almeno lo storage molto più efficiente usando a Uint16Array. La toStringfunzione dovrebbe usare la rappresentazione binaria in un JavaScriptobject
Sebastian

Questi UUID prodotti da questo codice sono deboli ma conformi a RFC (_guid) o resistenti ma non conformi a RFC (_cryptoGuid). Il primo utilizza Math.random (), che ora è noto per essere un RNG scadente. Quest'ultimo non riesce a impostare i campi versione e variante.
broofa,

@broofa - Cosa consiglieresti per renderlo forte e conforme a RFC? E perché _cryptoGuid non è conforme a RFC?
Matt

@Matt _cryptoGuid () imposta tutti i 128 bit in modo casuale, il che significa che non imposta i campi versione e variante come descritto nella RFC. Vedi la mia implementazione alternativa di uuidv4 () che utilizza crypto.getRandomValues ​​() nella mia risposta più votata, sopra, per un'implementazione forte + conforme.
broofa,

29

Questo crea l'UUID versione 4 (creato da numeri pseudo casuali):

function uuid()
{
   var chars = '0123456789abcdef'.split('');

   var uuid = [], rnd = Math.random, r;
   uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
   uuid[14] = '4'; // version 4

   for (var i = 0; i < 36; i++)
   {
      if (!uuid[i])
      {
         r = 0 | rnd()*16;

         uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
      }
   }

   return uuid.join('');
}

Ecco un esempio degli UUID generati:

682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136

28

Bene, questo ha già un sacco di risposte, ma sfortunatamente non c'è un "vero" casuale nel gruppo. La versione seguente è un adattamento della risposta di broofa, ma aggiornata per includere una "vera" funzione casuale che utilizza le librerie di crittografia ove disponibili e la funzione Alea () come fallback.

  Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
  Math.trueRandom = (function() {
  var crypt = window.crypto || window.msCrypto;

  if (crypt && crypt.getRandomValues) {
      // if we have a crypto library, use it
      var random = function(min, max) {
          var rval = 0;
          var range = max - min;
          if (range < 2) {
              return min;
          }

          var bits_needed = Math.ceil(Math.log2(range));
          if (bits_needed > 53) {
            throw new Exception("We cannot generate numbers larger than 53 bits.");
          }
          var bytes_needed = Math.ceil(bits_needed / 8);
          var mask = Math.pow(2, bits_needed) - 1;
          // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111

          // Create byte array and fill with N random numbers
          var byteArray = new Uint8Array(bytes_needed);
          crypt.getRandomValues(byteArray);

          var p = (bytes_needed - 1) * 8;
          for(var i = 0; i < bytes_needed; i++ ) {
              rval += byteArray[i] * Math.pow(2, p);
              p -= 8;
          }

          // Use & to apply the mask and reduce the number of recursive lookups
          rval = rval & mask;

          if (rval >= range) {
              // Integer out of acceptable range
              return random(min, max);
          }
          // Return an integer that falls within the range
          return min + rval;
      }
      return function() {
          var r = random(0, 1000000000) / 1000000000;
          return r;
      };
  } else {
      // From https://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <baagoe@baagoe.com>, 2010
      function Mash() {
          var n = 0xefc8249d;

          var mash = function(data) {
              data = data.toString();
              for (var i = 0; i < data.length; i++) {
                  n += data.charCodeAt(i);
                  var h = 0.02519603282416938 * n;
                  n = h >>> 0;
                  h -= n;
                  h *= n;
                  n = h >>> 0;
                  h -= n;
                  n += h * 0x100000000; // 2^32
              }
              return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
          };

          mash.version = 'Mash 0.9';
          return mash;
      }

      // From http://baagoe.com/en/RandomMusings/javascript/
      function Alea() {
          return (function(args) {
              // Johannes Baagøe <baagoe@baagoe.com>, 2010
              var s0 = 0;
              var s1 = 0;
              var s2 = 0;
              var c = 1;

              if (args.length == 0) {
                  args = [+new Date()];
              }
              var mash = Mash();
              s0 = mash(' ');
              s1 = mash(' ');
              s2 = mash(' ');

              for (var i = 0; i < args.length; i++) {
                  s0 -= mash(args[i]);
                  if (s0 < 0) {
                      s0 += 1;
                  }
                  s1 -= mash(args[i]);
                  if (s1 < 0) {
                      s1 += 1;
                  }
                  s2 -= mash(args[i]);
                  if (s2 < 0) {
                      s2 += 1;
                  }
              }
              mash = null;

              var random = function() {
                  var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                  s0 = s1;
                  s1 = s2;
                  return s2 = t - (c = t | 0);
              };
              random.uint32 = function() {
                  return random() * 0x100000000; // 2^32
              };
              random.fract53 = function() {
                  return random() +
                      (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
              };
              random.version = 'Alea 0.9';
              random.args = args;
              return random;

          }(Array.prototype.slice.call(arguments)));
      };
      return Alea();
  }
}());

Math.guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)    {
      var r = Math.trueRandom() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
  });
};

27

Progetto JavaScript su GitHub - https://github.com/LiosK/UUID.js

UUID.js Il generatore UUID conforme a RFC per JavaScript.

Vedi RFC 4122 http://www.ietf.org/rfc/rfc4122.txt .

Funzionalità Genera UUID conformi a RFC 4122.

Sono disponibili UUID versione 4 (UUID da numeri casuali) e UUID versione 1 (UUID basati sul tempo).

L'oggetto UUID consente una varietà di accesso all'UUID, incluso l'accesso ai campi UUID.

Una risoluzione timestamp bassa di JavaScript è compensata da numeri casuali.


21
  // RFC 4122
  //
  // A UUID is 128 bits long
  //
  // String representation is five fields of 4, 2, 2, 2, and 6 bytes.
  // Fields represented as lowercase, zero-filled, hexadecimal strings, and
  // are separated by dash characters
  //
  // A version 4 UUID is generated by setting all but six bits to randomly
  // chosen values
  var uuid = [
    Math.random().toString(16).slice(2, 10),
    Math.random().toString(16).slice(2, 6),

    // Set the four most significant bits (bits 12 through 15) of the
    // time_hi_and_version field to the 4-bit version number from Section
    // 4.1.3
    (Math.random() * .0625 /* 0x.1 */ + .25 /* 0x.4 */).toString(16).slice(2, 6),

    // Set the two most significant bits (bits 6 and 7) of the
    // clock_seq_hi_and_reserved to zero and one, respectively
    (Math.random() * .25 /* 0x.4 */ + .5 /* 0x.8 */).toString(16).slice(2, 6),

    Math.random().toString(16).slice(2, 14)].join('-');

16

Volevo capire la risposta di Broofa, quindi l'ho ampliata e ho aggiunto commenti:

var uuid = function () {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
        /[xy]/g,
        function (match) {
            /*
            * Create a random nibble. The two clever bits of this code:
            *
            * - Bitwise operations will truncate floating point numbers
            * - For a bitwise OR of any x, x | 0 = x
            *
            * So:
            *
            * Math.random * 16
            *
            * creates a random floating point number
            * between 0 (inclusive) and 16 (exclusive) and
            *
            * | 0
            *
            * truncates the floating point number into an integer.
            */
            var randomNibble = Math.random() * 16 | 0;

            /*
            * Resolves the variant field. If the variant field (delineated
            * as y in the initial string) is matched, the nibble must
            * match the mask (where x is a do-not-care bit):
            *
            * 10xx
            *
            * This is achieved by performing the following operations in
            * sequence (where x is an intermediate result):
            *
            * - x & 0x3, which is equivalent to x % 3
            * - x | 0x8, which is equivalent to x + 8
            *
            * This results in a nibble between 8 inclusive and 11 exclusive,
            * (or 1000 and 1011 in binary), all of which satisfy the variant
            * field mask above.
            */
            var nibble = (match == 'y') ?
                (randomNibble & 0x3 | 0x8) :
                randomNibble;

            /*
            * Ensure the nibble integer is encoded as base 16 (hexadecimal).
            */
            return nibble.toString(16);
        }
    );
};

Grazie per la descrizione dettagliata! In particolare uno stuzzichino in gabbia tra 8 e 11 con spiegazione equivalente è super utile.
Egor Litvinchuk,

15

Ho modificato il mio generatore UUID / GUID con alcuni extra qui .

sto usando i seguenti Kybo generatore di numeri casuali per essere un po 'più crittograficamente valido.

Di seguito è riportato il mio copione con i metodi Mash e Kybos di baagoe.com esclusi.

//UUID/Guid Generator
// use: UUID.create() or UUID.createSequential()
// convenience:  UUID.empty, UUID.tryParse(string)
(function(w){
  // From http://baagoe.com/en/RandomMusings/javascript/
  // Johannes Baagøe <baagoe@baagoe.com>, 2010
  //function Mash() {...};

  // From http://baagoe.com/en/RandomMusings/javascript/
  //function Kybos() {...};

  var rnd = Kybos();

  //UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
  var UUID = {
    "empty": "00000000-0000-0000-0000-000000000000"
    ,"parse": function(input) {
      var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
      if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
        return ret;
      else
        throw new Error("Unable to parse UUID");
    }
    ,"createSequential": function() {
      var ret = new Date().valueOf().toString(16).replace("-","")
      for (;ret.length < 12; ret = "0" + ret);
      ret = ret.substr(ret.length-12,12); //only least significant part
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"create": function() {
      var ret = "";
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"random": function() {
      return rnd();
    }
    ,"tryParse": function(input) {
      try {
        return UUID.parse(input);
      } catch(ex) {
        return UUID.empty;
      }
    }
  };
  UUID["new"] = UUID.create;

  w.UUID = w.Guid = UUID;
}(window || this));

15

Per coloro che desiderano una soluzione conforme a rfc4122 versione 4 con considerazioni sulla velocità (poche chiamate a Math.random ()):

var rand = Math.random;

function UUID() {
    var nbr, randStr = "";
    do {
        randStr += (nbr = rand()).toString(16).substr(3, 6);
    } while (randStr.length < 30);
    return (
        randStr.substr(0, 8) + "-" +
        randStr.substr(8, 4) + "-4" +
        randStr.substr(12, 3) + "-" +
        ((nbr*4|0)+8).toString(16) + // [89ab]
        randStr.substr(15, 3) + "-" +
        randStr.substr(18, 12)
    );
}

console.log( UUID() );

La funzione sopra dovrebbe avere un discreto equilibrio tra velocità e casualità.


13

Campione ES6

const guid=()=> {
  const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
  return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}

12

Il modo migliore:

function(
  a,b                // placeholders
){
  for(               // loop :)
      b=a='';        // b - result , a - numeric variable
      a++<36;        // 
      b+=a*51&52  // if "a" is not 9 or 14 or 19 or 24
                  ?  //  return a random number or 4
         (
           a^15      // if "a" is not 15
              ?      // genetate a random number from 0 to 15
           8^Math.random()*
           (a^20?16:4)  // unless "a" is 20, in which case a random number from 8 to 11
              :
           4            //  otherwise 4
           ).toString(16)
                  :
         '-'            //  in other cases (if "a" is 9,14,19,24) insert "-"
      );
  return b
 }

ridotti al minimo:

function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}

11

Lo so, è una vecchia domanda. Per completezza, se l'ambiente è SharePoint, esiste una funzione di utilità chiamata SP.Guid.newGuid( collegamento msdn ) che crea una nuova guida. Questa funzione si trova nel file sp.init.js. Se riscrivi questa funzione (per rimuovere alcune altre dipendenze da altre funzioni private), si presenta così:

var newGuid = function () {
    var result = '';
    var hexcodes = "0123456789abcdef".split("");

    for (var index = 0; index < 32; index++) {
        var value = Math.floor(Math.random() * 16);

        switch (index) {
        case 8:
            result += '-';
            break;
        case 12:
            value = 4;
            result += '-';
            break;
        case 16:
            value = value & 3 | 8;
            result += '-';
            break;
        case 20:
            result += '-';
            break;
        }
        result += hexcodes[value];
    }
    return result;
};

11

Questo si basa sulla data e aggiunge un suffisso casuale per "garantire" unicità. Funziona bene con identificatori CSS. Restituisce sempre qualcosa di simile ed è facile da hackerare:

uid-139410573297741

var getUniqueId = function (prefix) {
            var d = new Date().getTime();
            d += (parseInt(Math.random() * 100)).toString();
            if (undefined === prefix) {
                prefix = 'uid-';
            }
            d = prefix + d;
            return d;
        };

11

Codice semplice che utilizza crypto.getRandomValues(a)sui browser supportati (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Evita l'uso Math.random()perché ciò può causare collisioni (ad esempio 20 collisioni per 4000 uuidi generati in una situazione reale da Muxa ).

function uuid() {
    function randomDigit() {
        if (crypto && crypto.getRandomValues) {
            var rands = new Uint8Array(1);
            crypto.getRandomValues(rands);
            return (rands[0] % 16).toString(16);
        } else {
            return ((Math.random() * 16) | 0).toString(16);
        }
    }
    var crypto = window.crypto || window.msCrypto;
    return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit);
}

Appunti:

  • Ottimizzato per la leggibilità del codice non per la velocità, quindi adatto per dire poche centinaia di uuid al secondo. Genera circa 10000 uuid () al secondo in Chromium sul mio laptop usando http://jsbin.com/fuwigo/1 per misurare le prestazioni.
  • Usa solo 8 per "y" perché ciò semplifica la leggibilità del codice (y può essere 8, 9, A o B).

11

Se hai solo bisogno di una stringa casuale a 128 bit in nessun formato particolare puoi usare:

function uuid() {
    return crypto.getRandomValues(new Uint32Array(4)).join('-');
}

Che restituirà qualcosa di simile 2350143528-4164020887-938913176-2513998651.


A proposito, perché genera solo numeri e non caratteri? molto meno sicuro
vsync il

1
puoi anche aggiungere caratteri (lettere) in questo modo:Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
magikMaker

11

Solo un'altra variante più leggibile con solo due mutazioni.

function uuid4()
{
  function hex (s, b)
  {
    return s +
      (b >>> 4   ).toString (16) +  // high nibble
      (b & 0b1111).toString (16);   // low nibble
  }

  let r = crypto.getRandomValues (new Uint8Array (16));

  r[6] = r[6] >>> 4 | 0b01000000; // Set type 4: 0100
  r[8] = r[8] >>> 3 | 0b10000000; // Set variant: 100

  return r.slice ( 0,  4).reduce (hex, '' ) +
         r.slice ( 4,  6).reduce (hex, '-') +
         r.slice ( 6,  8).reduce (hex, '-') +
         r.slice ( 8, 10).reduce (hex, '-') +
         r.slice (10, 16).reduce (hex, '-');
}

Beh, la maggior parte degli sviluppatori js sono sviluppatori web e non capiremo cosa fanno gli operatori bit a bit, perché non li usiamo la maggior parte delle volte che sviluppiamo. In realtà non ne ho mai avuto bisogno, e sono un dev js dal '97. Quindi il tuo codice di esempio è ancora totalmente illeggibile per lo sviluppatore web medio che lo leggerà. Per non parlare del fatto che usi ancora nomi di variabili a lettera singola, il che lo rende ancora più criptico. Probabilmente leggi Clean Code, forse che aiuta: amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
inf3rno

@inf3rno non lo colpiscono, tutte le soluzioni proposte in questo thread sono criptiche ma sono risposte corrette considerando che la domanda era quella di avere una sorta di linea. questo è ciò che è un enigmatico. non possono permettersi di essere leggibili dallo sviluppatore medio, ma salvano lo schermo immobiliare dove farà un semplice commento precedente. E di conseguenza, finisce per essere molto più leggibile in quel modo se invece fosse stato in "codice leggibile".
Tatsu,

Casuale! = Unico
user1529413

@ user1529413 Sì. L'unicità richiede un indice.
Sperimento il

Questa è la mia risposta preferita, perché sta costruendo un UUID come valore di 16 byte (128 bit) e non il suo modulo serializzato, piacevole da leggere. Sarebbe banalmente facile far cadere la stringa e impostare semplicemente i bit corretti di un 128bit casuale, che è tutto ciò che un uuidv4 deve essere. Potresti basarlo64 per URL più brevi, passarlo a qualche assemblaggio web, archiviarlo in meno spazio di memoria rispetto a una stringa, renderlo un buffer di dimensioni 4096 e inserirvi 256 uid, archiviarlo in un db del browser, ecc. Molto meglio che avere tutto come una lunga stringa minuscola con codifica esadecimale dall'inizio.
Josh di Qaribou il

8

OK, usando il pacchetto uuid , supporta gli UUID versione 1, 3, 4 e 5 :

yarn add uuid

e poi:

const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '45745c60-7b1a-11e8-9c9c-2d42b21b1a3e'

Puoi anche farlo con le opzioni completamente specificate:

const v1options = {
  node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
  clockseq: 0x1234,
  msecs: new Date('2011-11-01').getTime(),
  nsecs: 5678
};
uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'

Per maggiori informazioni, visita la pagina npm qui


6

È importante utilizzare un codice ben collaudato gestito da più di 1 contributori invece di montare le tue cose per questo. Questo è uno dei luoghi in cui probabilmente si desidera preferire il codice più stabile rispetto alla versione intelligente più breve possibile che funziona nel browser X ma non tiene conto delle idiosincrasie di Y che spesso porterebbero a investigazioni molto difficili che si manifestano solo casualmente per alcuni utenti. Personalmente utilizzo uuid-js su https://github.com/aurigadl/uuid-js che abilita il bower in modo da poter prendere facilmente gli aggiornamenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.