在JavaScript中创建GUID / UUID?

时间:2008-09-19 20:01:00

标签: javascript guid uuid

我正在尝试在JavaScript中创建全局唯一标识符。我不确定所有浏览器上可用的例程,“随机”和内置随机数生成器的种子等等。

GUID / UUID应该至少为32个字符,并且应该保持在ASCII范围内,以避免在传递它们时出现问题。

69 个答案:

答案 0 :(得分:3519)

对于符合RFC4122版本4的解决方案,这种单线程(ish)解决方案是我能想到的最紧凑的解决方案。:

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

更新,2015-06-02 :请注意,UUID唯一性在很大程度上依赖于底层随机数生成器(RNG)。上面的解决方案使用Math.random()来简化,但Math.random() 保证是高质量的RNG。有关详细信息,请参阅Adam Hyland的excellent writeup on Math.random()。对于更强大的解决方案,请考虑the uuid module [免责声明:我是作者],它使用更高质量的RNG API。

更新,2015-08-26 :作为旁注,此gist介绍了如何确定在达到一定的碰撞概率之前可以生成多少个ID。例如,对于3.26x10 15 版本4 RFC4122 UUID,您有一个百万分之一的碰撞机会。

更新,2017-06-28 good article from Chrome developers讨论Chrome,Firefox和Safari中Math.random PRNG质量的状态。 tl; dr - 截至2015年底它“非常好”,但不是加密质量。要解决该问题,以下是使用ES6,crypto API和a bit of JS wizardy I can't take credit for的上述解决方案的更新版本:

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

答案 1 :(得分:2144)

根据RFC 4122,UUID(通用唯一标识符),也称为GUID(全局唯一标识符),是具有特定唯一性保证的标识符。

生成它们的最佳方法是遵循上述RFC中的实现说明,使用众多社区审核的开源实现之一。

用于在JavaScript中使用UUID的流行开源工具是node-uuid

请注意,只是逐字节或逐字符地随机生成标识符,不会为符合要求的实现提供相同的保证。此外,非常重要的是,使用兼容UUID的系统可能会选择不接受随机生成的系统,并且许多开源验证器实际上会检查有效的结构。

UUID必须具有以下格式:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

M N 位置可能只有某些值。此时,M的唯一有效值为1,2,3,4和5,因此随机生成该位置会使大多数结果无法接受。

答案 2 :(得分:741)

我真的很喜欢干净Broofa's answer,但遗憾的是Math.random的不良实现会让碰撞失效。

这是一个类似的RFC4122版本4兼容解决方案,通过将前13个十六进制数字偏移时间戳的十六进制部分来解决该问题。这样,即使Math.random位于同一种子上,两个客户端也必须在完全相同的毫秒(或10,000多年后)生成UUID才能获得相同的UUID:

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();
    if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
        d += performance.now(); //use high-precision timer if available
    }
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = (d + Math.random() * 16) % 16 | 0;
        d = Math.floor(d / 16);
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}


Here's a fiddle to test.

答案 3 :(得分:367)

broofa的答案非常光滑,确实 - 令人印象深刻的聪明,真的... rfc4122兼容,有点可读,紧凑。真棒!

但是如果你正在查看那个正则表达式,那么多replace()次回调,toString()Math.random()函数调用(他只使用4位结果并浪费其余的),你可能开始怀疑性能。实际上,joelpt甚至决定使用generateQuickGUID将RFC转换为通用GUID速度。

但是,我们可以获得速度 RFC合规性吗?我说,是的!我们能保持可读性吗?嗯...不是真的,但是如果你跟着它就很容易。

但首先,我的结果与broofa相比,guid(接受的答案)和非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.

因此,通过我的第6次优化迭代,我超过 12X ,超过 9X 接受的答案,以及快速不符合要求的答案,打败了最受欢迎的答案通过 2-3X 。我仍然符合rfc4122。

对如何感兴趣?我已将完整的来源放在http://jsfiddle.net/jcward/7hyaC/3/http://jsperf.com/uuid-generator-opt/4

要获得解释,让我们从broofa的代码开始:

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

所以它用任意随机十六进制数字替换x y随机数据(除了根据RFC规范将前2位强制为10),并且正则表达式没有匹配-4字符,因此他不必处理它们。非常非常光滑。

要知道的第一件事是函数调用很昂贵,正则表达式也是如此(尽管他只使用1,它有32个回调,每个匹配一个,并且在32个回调中它调用Math.random()和v.toString(16))。

性能的第一步是消除RegEx及其回调函数,而是使用简单的循环。这意味着我们必须处理-4字符,而broofa则不然。另请注意,我们可以使用String Array索引来保持其光滑的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;
}

基本上,相同的内部逻辑,除了我们检查-4,并使用while循环(而不是replace()回调),我们几乎提高了3倍!

下一步是桌面上的一个小步骤,但在移动设备上有一个不错的区别。让我们减少Math.random()调用并利用所有这些随机位,而不是使用随机缓冲区抛出87%的随机缓冲区,每次迭代都会移出它们。我们还将该模板定义移出循环,以防它有所帮助:

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
}

根据平台,这节省了10-30%。不错。但是下一个重要的步骤完全消除了toString函数调用与优化经典 - 查找表。一个简单的16元素查找表将在更短的时间内执行toString(16)的工作:

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
}

下一个优化是另一个经典。由于我们在每次循环迭代中只处理4位输出,所以让我们将循环次数减半,每次迭代处理8位。这很棘手,因为我们仍然需要处理符合RFC的位位置,但这并不难。然后我们必须创建一个更大的查找表(16x16或256)来存储0x00 - 0xff,我们只在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
}

我尝试了一次处理16位的e6(),仍然使用256个元素的LUT,它显示了优化的收益递减。虽然迭代次数较少,但内部逻辑因处理增加而变得复杂,并且在桌面上执行相同,在移动设备上的速度仅提高了约10%。

要应用的最终优化技术 - 展开循环。由于我们循环固定次数,我们可以在技术上手动写出这一切。我用一个随机变量r尝试了一次,我不断重新分配,并且性能下降了。但是有四个变量预先分配随机数据,然后使用查找表,并应用适当的RFC位,这个版本将它们全部抽出:

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

模块化:http://jcward.com/UUID.js - UUID.generate()

有趣的是,生成16字节的随机数据很容易。整个技巧是以符合RFC的字符串格式表达它,并且使用16字节的随机数据,一个展开的循环和查找表来完成它。

我希望我的逻辑是正确的 - 在这种乏味的工作中犯错误很容易。但输出对我来说很好看。我希望你通过代码优化享受这种疯狂的旅程!

建议:我的主要目标是展示和教授潜在的优化策略。其他答案涵盖了重要的主题,如冲突和真正的随机数,这对于生成良好的UUID非常重要。

答案 4 :(得分:147)

以下是一些基于RFC 4122的代码,第4.4节(从真正的随机数或伪随机数创建UUID的算法)。

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

答案 5 :(得分:106)

var uniqueId = Math.random().toString(36).substring(2) 
               + (new Date()).getTime().toString(36);

&#13;
&#13;
document.getElementById("unique").innerHTML =
  Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
&#13;
<div id="unique">
</div>
&#13;
&#13;
&#13;

如果ID的生成间隔超过1毫秒,则它们是100%唯一的。

如果以较短的间隔生成两个ID,并且假设随机方法是真正随机的,那么这将生成99.99999999999999%可能是全局唯一的ID(在10 ^ 1中的碰撞) 15)

您可以通过添加更多数字来增加此数字,但要生成100%唯一ID,您需要使用全局计数器。

如果您确实需要符合RFC,则此格式将作为有效版本4 GUID传递:

var u = (new Date()).getTime().toString(16) + 
    Math.random().toString(16).substring(2) + "0".repeat(16);
var guid = u.substr(0,8) + '-' + u.substr(8,4) + '-4000-8' + 
    u.substr(12,3) + '-' + u.substr(15,12);

&#13;
&#13;
var u = (new Date()).getTime().toString(16) + 
    Math.random().toString(16).substring(2) + "0".repeat(16);
var guid = u.substr(0,8) + '-' + u.substr(8,4) + '-4000-8' + 
    u.substr(12,3) + '-' + u.substr(15,12);
document.getElementById("unique").innerHTML = guid;
&#13;
<div id="unique">
</div>
&#13;
&#13;
&#13;

编辑:上面的代码遵循内涵,但不是RFC的字母。在其他差异中,它有几个随机数字。 (如果需要,可以添加更多随机数字)优点是,与100%兼容的代码相比,这非常快。 你可以test your GUID here

答案 6 :(得分:84)

最快的GUID,如格式为XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX的字符串生成器方法。这不会生成符合标准的GUID。

这个实现的1000万次执行只需32.5秒,这是我在浏览器中见过的最快的(没有循环/迭代的唯一解决方案)。

该功能非常简单:

/**
 * Generates a GUID string.
 * @returns {String} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser (slavik@meltser.info).
 * @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();
}

要测试性能,可以运行以下代码:

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

我相信大多数人都会理解我在那里所做的事情,但也许至少有一个人需要解释:

算法:

  • Math.random()函数返回0到1之间的十进制数,小数点后的16位数(for 例如0.4363923368509859)。
  • 然后我们拿这个号码转换 它是一个基数为16的字符串(从上面的例子我们得到 0.6fb7687f)。
    Math.random().toString(16)
  • 然后我们切断0.前缀(0.6fb7687f =&gt; 6fb7687f)并获取一个包含八个十六进制的字符串 人物长 (Math.random().toString(16).substr(2,8)
  • 有时Math.random()函数会返回 较短的数字(例如0.4363),由于末尾的零(从上面的示例中,实际上数字是0.4363000000000000)。这就是为什么我要附加到这个字符串"000000000"(一个包含九个零的字符串),然后使用substr()函数将其删除,使其准确地为九个字符(在右边填充零)。
  • 恰好添加九个零的原因是由于更糟糕的情况,即Math.random()函数将正好返回0或1(其中每一个的概率为1/10 ^ 16)。这就是为什么我们需要向它添加九个零("0"+"000000000""1"+"000000000"),然后从长度为八个字符的第二个索引(第三个字符)中删除它。对于其余的情况,添加零不会损害结果,因为无论如何它都会切断它 Math.random().toString(16)+"000000000").substr(2,8)

大会:

  • GUID采用以下格式XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
  • 我将GUID分为4个部分,每部分分为2种类型(或格式):XXXXXXXX-XXXX-XXXX
  • 现在,我正在使用这两种类型构建GUID,以使用调用4件来组合GUID,如下所示:XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX
  • 为了区分这两种类型,我在对创建者函数_p8(s)中添加了一个flag参数,s参数告诉函数是否添加破折号。
  • 最后,我们使用以下链接构建GUID:_p8() + _p8(true) + _p8(true) + _p8(),并将其返回。

Link to this post on my blog

享受! : - )

答案 7 :(得分:62)

以下是top voted answer的组合,以及Chrome's collisions的解决方法:

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // https://stackoverflow.com/questions/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
        // https://stackoverflow.com/questions/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);
        });
    };

On jsbin如果你想测试它。

答案 8 :(得分:56)

这是一个完全不兼容但非常高效的实现,可以生成类似于ASCII的GUID唯一标识符。

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

生成26个[a-z0-9]字符,产生的UID比RFC兼容的GUID更短且更独特。如果人类可读性很重要,可以简单地添加破折号。

以下是此功能的使用示例和时间以及此问题的其他几个答案。计时在Chrome m25下进行,每次迭代1000万次。

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

这是时间码。

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

答案 9 :(得分:56)

以下是2011年10月9日用户 jed 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)}

这实现了与current highest-rated answer相同的目标,但通过利用强制,递归和指数表示法减少了50多个字节。对于那些好奇的工作方式,这里是旧版本函数的注释形式:

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

答案 10 :(得分:36)

来自sagi shkedy's technical blog

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

还有其他方法涉及使用ActiveX控件,但远离这些!

编辑:我认为值得指出的是,没有GUID生成器可以保证唯一键(请查看wikipedia article)。始终存在碰撞的可能性。 GUID只提供足够大的键,以将碰撞的变化减少到几乎为零。

答案 11 :(得分:33)

您可以使用node-uuid(https://github.com/kelektiv/node-uuid

简单快速生成RFC4122 UUIDS。

特点:

  • 生成RFC4122版本1或版本4 UUID
  • 在node.js和浏览器中运行。
  • 支持平台上的密码强随机#生成。
  • 占地面积小(想要更小的东西?Check this out!

使用NPM安装:

npm install uuid

或通过浏览器使用uuid:

下载原始文件(uuid v1):https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js 下载原始文件(uuid v4):https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js

想要更小?看看这个:https://gist.github.com/jed/982883

<强>用法:

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

答案 12 :(得分:31)

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

编辑:

重温我正在使用此功能的项目并且不喜欢详细程度。 - 但需要适当的随机性。

基于Briguy37答案的版本和一些按位运算符从缓冲区中提取半字节大小的窗口。

应该遵循RFC Type 4(随机)模式,因为我上次使用Java的UUID解析不合规的uuids时出现问题。

答案 13 :(得分:31)

网络服务很有用。

快速Google发现:http://www.hoskinson.net/GuidGenerator/

无法保证此实现,但SOMEONE必须发布一个真正的GUID生成器。

使用这样的Web服务,您可以开发一个使用GUID Web服务的REST Web界面,并通过AJAX将其提供给浏览器中的javascript。

答案 14 :(得分:29)

简单的JavaScript模块,作为此主题中最佳答案的组合。

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

用法:

  
    

<强> Guid.newGuid()

         

“c6c2d12f-d76b-5739-e551-07e6de5b0807”

         

<强> Guid.empty

         

“00000000-0000-0000-0000-000000000000”

  

答案 15 :(得分:25)

good ol' wikipedia开始,有一个指向UUID的javascript实现的链接。

它看起来相当优雅,也许可以通过使用客户端IP地址的哈希来改进。可以将此哈希插入到html文档服务器端以供客户端javascript使用。

更新:原始网站有一个随机播放,这里是updated version

答案 16 :(得分:24)

嗯,这已经有了很多答案,但不幸的是,这一堆中并没有“真正的”随机。下面的版本是对broofa答案的改编,但更新后包括一个“真正的”随机函数,该函数在可用时使用加密库,而Alea()函数作为后备。

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

答案 17 :(得分:23)

这创建版本4 UUID(从伪随机数创建):

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

以下是生成的UUID示例:

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

答案 18 :(得分:23)

GitHub上的JavaScript项目 - https://github.com/LiosK/UUID.js

  

UUID.js适用于JavaScript的符合RFC的UUID生成器。

     

请参阅RFC 4122 http://www.ietf.org/rfc/rfc4122.txt

     

功能生成符合RFC 4122的UUID。

     

版本4 UUID(来自随机数的UUID)和版本1 UUID   (基于时间的UUID)可用。

     

UUID对象允许对UUID进行各种访问,包括访问权限   UUID字段。

     

JavaScript的低时间戳分辨率随机补偿   号。

答案 19 :(得分:16)

  // 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('-');

答案 20 :(得分:13)

使用一些额外内容here调整了我自己的UUID / GUID生成器。

我正在使用the following Kybos随机数生成器来加密声音。

以下是我的脚本,其中包含baagoe.com的Mash和Kybos方法。

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

答案 21 :(得分:12)

ES6样本

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

答案 22 :(得分:12)

更好的方法:

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
 }

最小化:

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}

答案 23 :(得分:12)

原生URL.createObjectURL正在生成一个uuid。您可以利用这一点。

function uuid() {
  const url = URL.createObjectURL(new Blob())
  const [id] = url.toString().split('/').reverse()
  URL.revokeObjectURL(url)
  return id
}

答案 24 :(得分:12)

我想了解布洛法的回答,所以我扩展了它并添加了评论:

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

答案 25 :(得分:11)

对于那些想要符合rfc4122版本4的解决方案而需要速度考虑的人(很少调用Math.random()):

function UUID() {
    var nbr, randStr = "";
    do {
        randStr += (nbr = Math.random()).toString(16).substr(2);
    } 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)
        ].join("");
}

上述功能应该在速度和随机性之间保持适当的平衡。

答案 26 :(得分:11)

这个基于日期,并添加随机后缀以“确保”唯一性。 适用于css标识符。 它总是返回类似的东西并且容易被破解:

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

答案 27 :(得分:11)

这只是一个简单的AJAX调用...

如果有人仍然感兴趣,这是我的解决方案。

在服务器端:

[WebMethod()]
public static string GenerateGuid()
{
    return Guid.NewGuid().ToString();
}

在客户端:

var myNewGuid = null;
PageMethods.GenerateGuid(
    function(result, userContext, methodName)
    {
        myNewGuid = result;
    },
    function()
    {
        alert("WebService call failed.");
    }
);

答案 28 :(得分:10)

我知道,这是一个老问题。为了完整起见,如果您的环境是SharePoint,则会有一个名为SP.Guid.newGuidmsdn link)的实用程序函数,它会创建一个新的guid。此函数位于sp.init.js文件中。如果你重写这个函数(从其他私有函数中删除一些其他依赖项),它看起来像这样:

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

答案 29 :(得分:10)

有一个jQuery插件可以很好地处理Guid的@ http://plugins.jquery.com/project/GUID_Helper

jQuery.Guid.Value()

返回内部Guid的值。如果没有指定guid,则返回一个新值(然后在内部存储值)。


jQuery.Guid.New()

返回一个新的Guid并在内部设置它的值。


jQuery.Guid.Empty()

返回空Guid 00000000-0000-0000-0000-000000000000。


jQuery.Guid.IsEmpty()

返回布尔值。如果为空/未定义/空白/空,则为真。


jQuery.Guid.IsValid()

返回布尔值。真正有效的guid,如果不是,则为false。


jQuery.Guid.Set()

Retrns Guid。将Guid设置为用户指定的Guid,如果无效,则返回空guid。

答案 30 :(得分:8)

如果你只需要一个没有特定格式的随机128位字符串,你可以使用:

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

将返回类似2350143528-4164020887-938913176-2513998651的内容。

答案 31 :(得分:6)

supported browsers上使用crypto.getRandomValues(a)的简单代码(IE11 +,iOS7 +,FF21 +,Chrome,Android Chrome)。避免使用Math.random(),因为这可能会导致冲突(例如Muxa实际情况下4000个生成的uuids发生20次冲突。)

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

注意:

  • 针对代码可读性而非速度进行了优化,因此适合每秒几百个uuid。使用http://jsbin.com/fuwigo/1在我的笔记本电脑上在Chromium中生成大约10000 uuid()每秒来测量性能。
  • 仅使用8代表&#34; y&#34;因为这简化了代码的可读性(允许y为8,9,A或B)。

答案 32 :(得分:6)

另一种更易读的变体只有两个突变。

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

答案 33 :(得分:5)

使用 Blob 的单行解决方案。

window.URL.createObjectURL(new Blob([])).substring(31);

末尾的值 (31) 取决于 URL 的长度。

答案 34 :(得分:5)

使用由超过1个贡献者维护的经过良好测试的代码而不是为此自行填充内容非常重要。这是你可能希望最喜欢最稳定的代码的地方之一,而不是在X浏览器中工作的最短的聪明版本,但不考虑Y的特性,这通常会导致非常难以调查错误,而不仅仅是随机显示对于一些用户。就个人而言,我在https://github.com/aurigadl/uuid-js使用了uuid-js,它启用了凉亭,因此我可以轻松获取更新。

答案 35 :(得分:4)

因为我可以,我认为我应该分享自己的解决方案,因为这是一个非常有趣的问题,并且有很多解决方案。

如果将let buffer = new Uint8Array(); crypto.getRandomValues替换为let buffer = crypto.randomBytes(16),则它也适用于nodejs

我希望它能对某人有所帮助。 它应该在性能上胜过大多数正则表达式解决方案。

const hex = '0123456789ABCDEF'

let generateToken = function() {
    let buffer = new Uint8Array(16)
    
    crypto.getRandomValues(buffer)

    buffer[6] = 0x40 | (buffer[6] & 0xF)
    buffer[8] = 0x80 | (buffer[8] & 0xF)

    let segments = []

    for (let i = 0; i < 16; ++i) {
        segments.push(hex[(buffer[i] >> 4 & 0xF)])
        segments.push(hex[(buffer[i] >> 0 & 0xF)])

        if (i == 3 || i == 5 || i == 7 || i == 9) {
            segments.push('-')
        }
    }

    return segments.join('')
}

for (let i = 0; i < 100; ++i) {
  console.log(generateToken())
}

性能图表,每个人都喜欢它们:jsbench

玩得开心,谢谢您提供所有其他解决方案,其中一些服务了我很长时间。

答案 36 :(得分:4)

最简单的函数:

function createGuid(){  
   let S4 = () => Math.floor((1+Math.random())*0x10000).toString(16).substring(1); 
   let guid = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
   
   return guid.toLowerCase();  
}

答案 37 :(得分:3)

一个老问题,所以它可能永远不会浮出水面,但是我已经在这里提到的所有内容的基础上产生了两倍快,可移植的所有环境(包括节点),并将其从Math.random()升级为加密强度随机性。您可能不认为uuid需要加密强度,但这意味着碰撞的机会更少,这就是uuid的全部要点。

function random() {
    const
        fourBytesOn = 0xffffffff, // 4 bytes, all 32 bits on: 4294967295
        c = typeof crypto === "object"
            ? crypto // node or most browsers
            : typeof msCrypto === "object" // stinky non-standard IE
                ? msCrypto // eslint-disable-line no-undef
                : null; // what old or bad environment are we running in?
        return c
            ? c.randomBytes
                ? parseInt(c.randomBytes(4).toString("hex"), 16) / (fourBytesOn + 1) - Number.EPSILON // node
                : c.getRandomValues(new Uint32Array(1))[0] / (fourBytesOn + 1) - Number.EPSILON // browsers
            : Math.random();
}

function uuidV4() { // eslint-disable-line complexity
    // if possible, generate a single random value, 128 bits (16 bytes) in length
    // in an environment where that is not possible, generate and make use of 4 32-bit (4-byte) random values
    // use crypto-grade randomness when available, else Math.random()
    const
        c = typeof crypto === "object"
            ? crypto // node or most browsers
            : typeof msCrypto === "object" // stinky non-standard IE
                ? msCrypto // eslint-disable-line no-undef
            : null; // what old or bad environment are we running in?
    let
        byteArray = c
            ? c.randomBytes
                ? c.randomBytes(16) // node
                : c.getRandomValues(new Uint8Array(16)) // browsers
            : null,
        uuid = [ ];

    /* eslint-disable no-bitwise */
    if ( ! byteArray) { // no support for generating 16 random bytes in one shot -- this will be slower
        const
            int = [
                random() * 0xffffffff | 0,
                random() * 0xffffffff | 0,
                random() * 0xffffffff | 0,
                random() * 0xffffffff | 0
            ];
        byteArray = [ ];
        for (let i = 0; i < 256; i++) {
            byteArray[i] = int[i < 4 ? 0 : i < 8 ? 1 : i < 12 ? 2 : 3] >> i % 4 * 8 & 0xff;
        }
    }
    byteArray[6] = byteArray[6] & 0x0f | 0x40; // always 4, per RFC, indicating the version
    byteArray[8] = byteArray[8] & 0x3f | 0x80; // constrained to [89ab], per RFC for version 4
    for (let i = 0; i < 16; ++i) {
        uuid[i] = (byteArray[i] < 16 ? "0" : "") + byteArray[i].toString(16);
    }
    uuid =
        uuid[ 0] + uuid[ 1] + uuid[ 2] + uuid[ 3] + "-" +
        uuid[ 4] + uuid[ 5]                       + "-" +
        uuid[ 6] + uuid[ 7]                       + "-" +
        uuid[ 8] + uuid[ 9]                       + "-" +
        uuid[10] + uuid[11] + uuid[12] + uuid[13] + uuid[14] + uuid[15];
    return uuid;
    /* eslint-enable no-bitwise */
}

答案 38 :(得分:3)

你可以使用npm包 guid ,一个guid生成器和验证器。

https://www.npmjs.com/package/guid

示例:

Guid.raw();
// -> '6fdf6ffc-ed77-94fa-407e-a7b86ed9e59d'

更新:此软件包已被弃用。请改用 uuid

https://www.npmjs.com/package/uuid

示例:

const uuidv4 = require('uuid/v4');
uuidv4(); // ⇨ '10ba038e-48da-487b-96e8-8d3b99b6d18a'

答案 39 :(得分:3)

我正在使用以下功能,希望它可能有用。

    function NewGuid()
         {
           var sGuid="";
           for (var i=0; i<32; i++)
            {
              sGuid+=Math.floor(Math.random()*0xF).toString(0xF);
            }
           return sGuid;
         }

答案 40 :(得分:3)

嗨,这是一个工作示例,它生成32位唯一UUID。

function generateUUID() {
      var d = new Date();
      var k = d.getTime();
     var str = k.toString(16).slice(1)
    var UUID= 'xxxx-xxxx-4xxx-yxxx-xzx'.replace(/[xy]/g, function (c)
      {
        var r = Math.random() * 16 | 0;
        v = c == 'x' ? r : (r & 3 | 8);
        return v.toString(16);
      });
      var newString = UUID.replace(/[z]/, str)
      return newString;
    }
    var x = generateUUID()
    console.log(x,x.length)

答案 41 :(得分:3)

万一有人通过谷歌搜索小型实用程序库,ShortId(https://www.npmjs.com/package/shortid)符合此问题的所有要求。它允许指定允许的字符和长度,并保证非顺序,非重复的字符串。

为了使这更像是一个真正的答案,该库的核心使用以下逻辑来生成其短ID:

function encode(lookup, number) {
    var loopCounter = 0;
    var done;

    var str = '';

    while (!done) {
        str = str + lookup( ( (number >> (4 * loopCounter)) & 0x0f ) | randomByte() );
        done = number < (Math.pow(16, loopCounter + 1 ) );
        loopCounter++;
    }
    return str;
}

/** Generates the short id */
function generate() {

    var str = '';

    var seconds = Math.floor((Date.now() - REDUCE_TIME) * 0.001);

    if (seconds === previousSeconds) {
        counter++;
    } else {
        counter = 0;
        previousSeconds = seconds;
    }

    str = str + encode(alphabet.lookup, version);
    str = str + encode(alphabet.lookup, clusterWorkerId);
    if (counter > 0) {
        str = str + encode(alphabet.lookup, counter);
    }
    str = str + encode(alphabet.lookup, seconds);

    return str;
}

我没有对此进行编辑以反映此方法的最基本部分,因此上述代码包含了库中的一些其他逻辑。如果您对它正在做的一切感到好奇,请查看来源:https://github.com/dylang/shortid/tree/master/lib

答案 42 :(得分:2)

对于我的用例,我要求id生成保证在全局范围内是唯一的;没有例外。我在这个问题上挣扎了一段时间,并提出了一个名为tuid(真正唯一ID)的解决方案。它生成一个id,前32个字符是系统生成的,其余数字表示自纪元以来的毫秒数。在我需要在客户端javascript上生成id的情况下,它运行良好。看看:

https://github.com/mongoh/tuid

答案 43 :(得分:2)

此产品从 a-z,0-9 返回 5 组 8 位数字 其中大部分是随机的,但包含一天中的时间,并且有一个随机递增的计数器。 您可以指定任何您喜欢的基数(十六进制、十进制、36),默认为每组 8 个随机选择一个基数,在基数 16 到 36 的范围内

function newId(base) {
return[
 Math.random,
 function (){ return (newId.last ? windowId.last + Math.random() : Math.random() ) },
 Math.random,
 Date.now,
 Math.random
].map(function(fn){
    return fn().toString(base||(16+(Math.random()*20))).substr(-8);
}).join('-');
}

var demo = function(base){
    document.getElementById('uuid').textContent = newId(base);
}
demo(16);
#uuid { font-family: monospace; font-size: 1.5em; }
<p id="uuid"></p>
<button onclick="demo(16);">Hex (base 16)</button>
<button onclick="demo(36);">Base 36</button>
<button onclick="demo(10);">Decimal (base 10)</button>
<button onclick="demo();">Random base</button>

答案 44 :(得分:2)

对于那些在Windows上使用Javascript的人(例如WScript / CScript / MSHTA)。可以使用ActiveX。具体来说,Scriptlet.Typelib对象:

WScript.Echo((new ActiveXObject("Scriptlet.TypeLib")).Guid)

请注意,此答案仅适用于我列出的技术,它不适用于任何浏览器,甚至不适用于Microsoft Edge!所以,你的里程会因这个答案而有所不同。

答案 45 :(得分:2)

这是一个从字符串生成静态 UUID 或随机 UUID(如果未提供字符串)的函数:

function stringToUUID (str)
{
  if (str === undefined || !str.length)
    str = "" + Math.random() * new Date().getTime() + Math.random();

  let c = 0,
      r = "";

  for (let i = 0; i < str.length; i++)
    c = (c + (str.charCodeAt(i) * (i + 1) - 1)) & 0xfffffffffffff;

  str = str.substr(str.length / 2) + c.toString(16) + str.substr(0, str.length / 2);
  for(let i = 0, p = c + str.length; i < 32; i++)
  {
    if (i == 8 || i == 12 || i == 16 || i == 20)
      r += "-";

    c = p = (str[(i ** i + p + 1) % str.length]).charCodeAt(0) + p + i;
    if (i == 12)
      c = (c % 5) + 1; //1-5
    else if (i == 16)
      c = (c % 4) + 8; //8-B
    else
      c %= 16; //0-F

    r += c.toString(16);
  }
  return r;
}

console.log("Random       :", stringToUUID());
console.log("Static [1234]:", stringToUUID("1234")); //29c2c73b-52de-4344-9cf6-e6da61cb8656
console.log("Static [test]:", stringToUUID("test")); //e39092c6-1dbb-3ce0-ad3a-2a41db98778c

jsfiddle

答案 46 :(得分:2)

基于broofa的工作,我通过将时间戳添加到math.random()来增加了一些随机性

希望这会有所帮助

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

答案 47 :(得分:2)

这只是一个概念,当然可以在很多方面进行改进,但并没有我想象的那么慢。

一般来说,此代码包含以毫秒为单位的十六进制编码时间戳(一些黑客可以提供 12 位数字,因此该代码即使在 2527-06-24 之后也能工作,但在 5138-11-16 之后则不能),这意味着它是可排序的.它不是那么随机,它使用 MAC address 作为最后 12 位数字。第 13 个字母被硬编码为 1,以保持可排序。

之后,接下来的6位数字来自半随机字符串,其中第一位数字来自该毫秒生成的记录计数,其他数字随机生成。该 6 位数字部分包含一个破折号和硬编码字母“a”,以保持记录可排序。

我知道这可以缩短,性能也可以提高,但我对结果很满意(MAC 地址除外)。

currentNanoseconds = () => {
  return nodeMode ? process.hrtime.bigint() : BigInt(Date.now() * 1000000);
}

nodeFindMacAddress = () => {
  // Extract MAC address
  const interfaces = require('os').networkInterfaces();
  let result = null;
  for (index in interfaces) {
    let entry = interfaces[index];
    entry.forEach(item => {
      if (item.mac !== '00:00:00:00:00:00') {
        result = '-' + item.mac.replace(/:/g, '');
      }
    });
  }
  return result;
}

const nodeMode = typeof(process) !== 'undefined';
let macAddress = nodeMode ? nodeFindMacAddress() : '-a52e99ef5efc';
let startTime = currentNanoseconds();


let uuids = []; // Array for storing generated UUIDs, useful for testing
let currentTime = null; // Holds the last value of Date.now(), used as a base for generating the UUID
let timePart = null; // Part of the UUID generated from Date.now()
let counter = 0; // Used for counting records created at certain millisecond
let lastTime = null; // Used for resetting the record counter

const limit = 1000000;

for (let testCounter = 0; testCounter < limit; testCounter++) {
  let uuid = testMe();

  if (nodeMode || testCounter <= 50) {
    uuids.push(uuid);
  }
}

const timePassed = Number(currentNanoseconds() - startTime);

if (nodeMode) {
  const fs = require('fs');
  fs.writeFileSync('temp.txt', JSON.stringify(uuids).replace(/,/g, ',\n'));
} else {
  console.log(uuids);
}

console.log({
  operationsPerSecond: (1000 * limit / timePassed).toString() + 'm',
  nanosecondsPerCycle: timePassed / limit,
  milliSecondsPassed: timePassed / 1000000,
  microSecondsPassed: timePassed / 1000,
  nanosecondsPassed: timePassed
});

function testMe() {
  currentTime = Date.now();
  let uuid = null; // Function result

  if (currentTime !== lastTime) {
    // Added a 9 before timestamp, so that the hex-encoded timestamp is 12 digits long. Currently, it is 11 digits long, and it will be until 2527-06-24
    // console.log(Date.parse("2527-06-24").toString(16).length)
    // Code will stop working on 5138-11-17, because the timestamp will be 15 digits long, and the code only handles up to 14 digit timestamps
    // console.log((Date.parse("5138-11-17")).toString().length)
    timePart = parseInt(('99999999999999' + currentTime).substr(-14)).toString(16);
    timePart = timePart.substr(0, 8) + '-' + timePart.substr(8, 4) + '-1';
    counter = 0;
  }

  randomPart = ('000000' + Math.floor(10 * (counter + Math.random()))).slice(-6);
  randomPart = randomPart.substr(0, 3) + '-a' + randomPart.substr(3, 3);
  uuid = timePart + randomPart + macAddress;

  counter++;

  lastTime = currentTime;

  return uuid;
}

答案 48 :(得分:2)

以下 uuid 实现提供了一个使用 BigInt不同 ES6 2020 解决方案,并侧重于“{{1} } 设计模式”;尤其适用于 indexedDb uuid 场景,在这些场景中,统一时间排序和整理很有价值。

<块引用>

所以,注意到这篇文章有 30 多个答案,这里是...

这篇文章有:

  1. 一个“TL;DR”primaryKey section 带有独立的 es6 code
  2. 一个用例动机 讨论 部分关于 es6 class Xuid 提供了代码

TL;DR class Xuid 解决方案使用单调时钟的通用 v4 class Xuid

以下代码摘自我编写并拥有的 Smallscript EdgeS 网络客户端库,并在此处提供,获得 MIT 许可。 一旦 EdgeS 网络客户端工具集发布,GitHub version 将可用。

<块引用>

使用示例:

评估:uuid
发出:console.log(Xuid.v4New)

{1eb4a659-8bdc-4ce0-c002-b1d505d38ea8}

动机

虽然 v4 class Xuid { //@ edges.sm.st, ess.dev: MIT license Smallscript/David Simmons 2020 //! Can't use `static const field = const` xbrowser (thus, const's duped) static get v4New() { const ns7Now = this.ns7Now, xnode48 = this.xnode48; let clock_seq13 // monotonic `clock_seq` guarantee (13-bits/time-quantum) if(ns7Now <= this.ns7Now_prevSeq && this.ns7Now_prevSeq) clock_seq13 = ((this.ns7Now_prevSeq += 1n) - ns7Now) & 0b1_1111_1111_1111n else clock_seq13 = 0n, this.ns7Now_prevSeq = ns7Now const time60 = ((ns7Now << 4n) & 0xFFFF_FFFF_FFFF_0000n) | (ns7Now & 0x0000_0000_0000_0FFFn), v4 = 0x1_00000000_0000_0000_0000_000000000000n | (time60 << 64n) | (0x00000000_0000_4000_0000_000000000000n) | // M: V4 (0b110n << 61n) | (clock_seq13 << 48n) | // N: Variant-2 time-seq collation xnode48, s = v4.toString(16)//.substr(1) return `{${s.substr(1,8)}-${s.substr(9,4)}-${s.substr(13,4)}-${ s.substr(17,4)}-${s.substr(21,12)}}` } static get xnode48()/*:<BigInt#48>*/{ if(this.xnode48_) return this.xnode48_ let clockSeqNode; if(typeof URL !== 'undefined' && URL.createObjectURL) { const url = URL.createObjectURL(new Blob()) const id = (url.toString().split('/').reverse()[0]).split('-') URL.revokeObjectURL(url) clockSeqNode = BigInt('0x'+id[3]+id[4]) } else { const a4 = this.a4; this.getRandomValues(this.a4); clockSeqNode = (BigInt(a4[2]) << 32n) | BigInt(a4[3]) } // simulate the 48-bit node-id and 13-bit clock-seq // to combine with 3-bit uuid-variant return this.xnode48_ = clockSeqNode & 0xFFFF_FFFF_FFFFn; } static get jdNow()/*:<double#ns7>*/{ // return 2440587.5+Date.now()/864e5 // <- Date-quantum-ms form (7ns form below) return this.jdFromNs7(this.ns7Now) } static get ns7Now()/*:<BigInt#60>*/{ if(typeof performance !== 'undefined' && performance.now) Reflect.defineProperty(this, 'ns7Now', Reflect.getOwnPropertyDescriptor(this,'ns7Now_performance')) else Reflect.defineProperty(this, 'ns7Now', Reflect.getOwnPropertyDescriptor(this, 'ns7Now_Date')) return this.ns7Now } static get ns7Now_Date()/*:<BigInt#60>*/{ // const epoch1582Ns7_bias = 0x1b2_1dd2_1381_4000 // V1 1582 Oct 15 // const epoch1601Ns7_bias = 0x19d_b1de_d53e_8000n // FILETIME base const epoch1970Ns7 = BigInt(Date.now() * 1000_0.0) return epoch1970Ns7 + 0x1b2_1dd2_1381_4000n } static get ns7Now_performance()/*:<BigInt#60>*/{ const epochPgNs7 = BigInt(performance.now()*/*15*/1000_0.0|/*17*/0) if(!this.epoch1970PgNs7) // performance.timing.navigationStart this.epoch1970PgNs7 = this.ns7Now_Date - epochPgNs7 return epochPgNs7 + this.epoch1970PgNs7 } static dateFromJd(jd) {return new Date((jd - 2440587.5) * 864e5)} static dateFromNs7(ns7) { return new Date(Number(ns7 - 0x1b2_1dd2_1381_4000n) / 1000_0.0)} static jdFromNs7(ns7) { // atomic-clock leap-seconds (ignored) return 2440587.5 + (Number(ns7 - 0x1b2_1dd2_1381_4000n) / 864e9) } static ns7FromJd(jd) { return BigInt((jd - 2440587.5) * 864e9) + 0x1b2_1dd2_1381_4000n } static getRandomValues(va/*:<Uint32Array>*/) { if(typeof crypto !== 'undefined' && crypto.getRandomValues) crypto.getRandomValues(va) else for(let i = 0, n = va.length; i < n; i += 1) va[i] = Math.random() * 0x1_0000_0000 >>> 0 } static get a4() {return this.a4_ || (this.a4_ = new Uint32Array(4))} static ntohl(v)/*:<BigInt>*/{ let r = '0x', sign = 1n, s = BigInt(v).toString(16) if(s[0] == '-') s = s.substr(1), sign = -1n for(let i = s.length; i > 0; i -= 2) r += (i == 1) ? ('0' + s[i-1]) : s[i-2] + s[i-1] return sign*BigInt(r) } static ntohl32(v)/*:<Number>*/{return Number(this.ntohl(v))} } 定义了一个基本随机的 uuid,但希望有一个可以支持一些附加特性的 uuid 实现。

  • 快速有效地创建新的 uuid(使用 uuid
  • 作为具有名义 BigInt可读80 loc的独立代码实现 附评论
  • class 中使用单调 uuid 来合并 time 唯一性
  • 字符串化使得字符串形式:
    • 根据 contexttime (使用 context Variant-2)进行整理
    • 转换回正确识别和恢复 uuid 的二进制形式
  • 在可用的情况下包含 time 微秒时钟精度
  • 支持基于 julian-day 的 100 纳秒单位的跨环境量子 纪元 1582 年 10 月 15 日,V1 兼容性。启用统一时间的选项 跨一系列环境和用例的行为一致 JavaScriptEdgeS language 模型。 <块引用>

    特别适合与 SQLite 等工具一起使用的数据库。

  • 使用 ESS 设计来简化标称工作的可扩展性以扩展 它提供其他 es6 class variants
  • 对于这个帖子,统一并整合了基本的uuid相关 eswc 库 API。
    • 儒略日 API
    • ns7 (100 纳秒量子) API
    • time API 用于方便重新排序 ntohl 字符串表示
  • 源自 QKS Smalltalk 1991,AOS® [敏捷对象系统;代理对象系统] 它保留的语言、框架和运行时的引擎家族技术 用例在广泛的当前和历史主机操作系统中的兼容性 楷模。
    • 特别是 BigInt 花括号引用的标量字符串格式 支持 Xuidguiduuid (uid, git, fossil repo-id) 表示,SqLite 等。 <块引用>

      如: FILETIME

  • 最后但并非最不重要的是,它提供了一种理想的工作解决方案 使用 indexedDb {1eb4a659-8bdc-4ce0-c002-b1d505d38ea8} 其中使用 object stores 作为 uuid 变得令人向往。
    • 启用自动排序功能
    • 自然字符串整理
      • 注意使用 primaryKey Variant-2 来反转 uuid 值的微妙 LHS 的字符串化形式。
    • 自然而简单的time更新
    • put 的自然模式(EdgeS 虚拟文件系统自动命名)
    • efsservice-worker 同步和复制操作

总结

虽然简洁,但希望这对现在来说已经足够了; 试试

而且,随时发表评论、提交反馈或建议。

作为 EdgeS 网络客户端 cloud-server 的一部分在 GitHub 上发布时 带有 eswcindexedDb 使用模式将作为其示例 设计意图,包括解决效率和可用性 indexedDb相关 PWA efssync 方案。

有关的

基准测试 replicate 秒/秒

uuid

结果: 值 16..20 => ~2 微秒 => 500,000 const start = Xuid.ns7Now for(let i = 100000; i; i -=1) Xuid.v4New const end = Xuid.ns7Now console.log(`Delta 7ns: ${(end-start)/100000n}`) s/sec

答案 49 :(得分:2)

基于crypto API的broofa从2017年6月28日起更新的打字稿版本:

function genUUID() {
        // Reference: https://stackoverflow.com/a/2117523/709884
        return ("10000000-1000-4000-8000-100000000000").replace(/[018]/g, s => {
            const c = Number.parseInt(s, 10)
            return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        })
}

原因:

  • +number[]之间使用number是无效的
  • stringnumber的转换必须明确

答案 50 :(得分:1)

内置时间戳记的UUID(发射器/解析器)
我还将发布简单的方法来生成具有非常强的唯一性和快速运行时间的有效UUID v4。基本思想并不新鲜,但是方法不同。我使用来自date.now()的时间戳(以毫秒为单位)(在Node.js库中,我将在后面指出,我使用来自process.hrtime.bigint()的纳秒时间戳),然后添加一个随机的5位数({{ 1}})到时间戳字符串的末尾。合并字符串后,我仅由数字和一对特殊字符组成一个有效的UUID,因此我的UUID仅由数字和一些非数字字符组成。请在下面查看:

10000-90000

查看结果,您显然会看到UUID的第一部分是相同的,然后是随机性。这是因为我将时间戳线性插入了UUID。该代码将每毫秒(在Node.js库中为纳秒)产生一个新的UUID,并在末尾添加一个随机的5位数字,因此最终得出的碰撞概率非常近似,约为每秒1000万分之一。如果使用Node.js库,则非常近似的碰撞几率将达到每秒100亿分之一。

UUID中内置的时间戳
由于我们将时间戳线性地插入到UUID中,因此我们获得了一项功能(好坏,取决于任务)-能够轻松地从UUID中提取此时间戳的功能。这样我们可以了解何时发布UUID:

/*
 * uuid-timestamp (emitter)
 * UUID v4 based on timestamp
 *
 * Created by tarkh
 * tarkh.com (C) 2020
 */
const uuidEmit = () => {
  // Get now time
  const n = Date.now();
  // Generate random
  const r = Math.random();
  // Stringify now time and generate additional random number
  const s = String(n) + String(~~(r*9e4)+1e4);
  // Form UUID and return it
  return `${s.slice(0,8)}-${s.slice(8,12)}-4${s.slice(12,15)}-${[8,9,'a','b'][~~(r*3)]}${s.slice(15,18)}-${s.slice(s.length-12)}`;
};

// Generate 5 UUIDs
console.log(`${uuidEmit()}
${uuidEmit()}
${uuidEmit()}
${uuidEmit()}
${uuidEmit()}`);

Node.js
上面的代码的NPM版本为Node.js module。此版本在生成唯一值方面更加强大,因为它使用系统时间和/* * uuid-timestamp (parser) * UUID v4 based on timestamp * * Created by tarkh * tarkh.com (C) 2020 */ const uuidParse = (uuid) => { // Get current timestamp string length let tl = String(Date.now()).length; // Strip out timestamp from UUID let ts = ''; let i = -1; while(tl--) { i++; if(i===8||i===13||i===14||i===18||i===19||i===23) { tl++; continue; } ts += uuid[i]; } return Number(ts); }; // Get the timestamp when UUID was emitted const time = uuidParse('15970688-7109-4530-8114-887109530114'); // Covert timestamp to date and print it console.log(new Date(time).toUTCString());时差的组合来使用nanoseconds而不是毫秒时间戳。

基准
在本文的结尾,我想根据本主题的一些答案进行性能测试。当然,我的决定不是最快的,但肯定是最重要的。
Check jsBench here

答案 51 :(得分:1)

创新。

实际上,在非Microsoft圈子中称为Guid或UUID只是一个128位加密随机数,而uuid版本号(1-5)位于固定位置字节。

因此,当您只是在0到65535之间生成一堆随机数并对其进行十六进制编码时,就像这样:

function guid()
{
    function s4()
    {
        return Math.floor(Math.random() * 65536).toString(16).padStart(4, '0')
    } // End Function s4 

    return s4() + s4() + '-' + s4() + '-' + "4" + s4().substr(1) + '-' + s4() + '-' + s4() + s4() + s4();
} // End Function guid 

您获得了有效的GUID,但是由于随机执行,因此它不是加密安全的。

要生成加密安全的GUID,您需要使用window.crypto(或Internet Exploder使用window.msCrypto)。

是这样的:

function cryptGuid()
{ 
    var array = new Uint16Array(8);
    (window.crypto || window.msCrypto).getRandomValues(array);
    var dataView = new DataView(array.buffer);
    
    var parts = [];

    for(var i = 0; i < array.length; ++i)
    {
        // 0&1,2,3,4,5-7 dataView.getUint16(0-7)
        if(i>1 && i<6) parts.push("-");
        parts.push(dataView.getUint16(i).toString(16).padStart(4, '0'));
    }

    parts[5] = "4" + parts[5].substr(1);
    // console.log(parts);
    return parts.join('').toUpperCase();// .toLowerCase();
}

cryptGuid();

此外,您必须决定是否将数字返回为小写或大写字符串。 某些软件要求使用小写字符(例如,Reporting Service),而其他软件则需要生成大写字符(SQL-Server)。

答案 52 :(得分:1)

在任何情况下都不要使用 Math.random ,因为它会生成非加密的随机数源

以下使用 crypto.getRandomValues

的解决方案
function uuidv4() {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
    // tslint:disable-next-line: no-bitwise
    const r =
      (window.crypto.getRandomValues(new Uint32Array(1))[0] *
        Math.pow(2, -32) * 16) |
      0;
    // tslint:disable-next-line: no-bitwise
    const v = c === "x" ? r : (r & 0x3) | 0x8;
    return v.toString(16);
  });
}

link帮助您了解Fortify Scanner引发的不安全随机性

答案 53 :(得分:1)

在这里你可以找到一个非常小的函数来生成uuids https://gist.github.com/jed/982883

其中一个最终版本是:

function b(
  a                  // placeholder
){
  var cryptoObj = window.crypto || window.msCrypto; // for IE 11
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      cryptoObj.getRandomValues(new Uint8Array(1))[0]  // 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
      )
}

答案 54 :(得分:1)

UUID当前有一个添加到标准库的建议,可以在https://github.com/tc39/proposal-uuid

处得到支持。

该建议包括以下UUID:

// We're not yet certain as to how the API will be accessed (whether it's in the global, or a
// future built-in module), and this will be part of the investigative process as we continue
// working on the proposal.
uuid(); // "52e6953d-edbe-4953-be2e-65ed3836b2f0"

此实现遵循与在此处找到的V4随机uuid生成相同的布局:https://www.npmjs.com/package/uuid

const uuidv4 = require('uuid/v4');
uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'

我认为值得注意的是,通过在标准库中有正式的实现,可以节省多少带宽。该提案的作者还指出:

每月从npm> 62,000,000次下载12 kb uuid模块(2019年6月);使其在标准库中可用最终可以在全球范围内节省TB的带宽。如果我们使用标准库继续满足用户需求(例如uuid),则可以节省带宽。

答案 55 :(得分:1)

这里有很多正确的答案,但是令人遗憾的是,包含的代码示例非常隐秘并且难以理解。这就是我创建版本4(随机)UUID的方式。

请注意,以下代码段使用二进制文字来提高可读性,因此需要ECMAScript 6。

节点版本

function uuid4() {
  let array = new Uint8Array(16)
  crypto.randomFillSync(array)

  // manipulate 9th byte
  array[8] &= 0b00111111 // clear first two bits
  array[8] |= 0b10000000 // set first two bits to 10

  // manipulate 7th byte
  array[6] &= 0b00001111 // clear first four bits
  array[6] |= 0b01000000 // set first four bits to 0100

  const pattern = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  let idx = 0

  return pattern.replace(
    /XX/g,
    () => array[idx++].toString(16).padStart(2, "0"), // padStart ensures leading zero, if needed
  )
}

浏览器版本

只有第二行是不同的。

function uuid4() {
  let array = new Uint8Array(16)
  crypto.getRandomValues(array)

  // manipulate 9th byte
  array[8] &= 0b00111111 // clear first two bits
  array[8] |= 0b10000000 // set first two bits to 10

  // manipulate 7th byte
  array[6] &= 0b00001111 // clear first four bits
  array[6] |= 0b01000000 // set first four bits to 0100

  const pattern = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  let idx = 0

  return pattern.replace(
    /XX/g,
    () => array[idx++].toString(16).padStart(2, "0"), // padStart ensures leading zero, if needed
  )
}

测试

最后是相应的测试(茉莉花)。

describe(".uuid4()", function() {
  it("returns a UUIDv4 string", function() {
    const uuidPattern = "XXXXXXXX-XXXX-4XXX-YXXX-XXXXXXXXXXXX"
    const uuidPatternRx = new RegExp(uuidPattern.
      replaceAll("X", "[0-9a-f]").
      replaceAll("Y", "[89ab]"))

    for (let attempt = 0; attempt < 1000; attempt++) {
      let retval = uuid4()
      expect(retval.length).toEqual(36)
      expect(retval).toMatch(uuidPatternRx)
    }
  })
})

解释了UUID v4

关于UUID版本4的很好解释在这里:https://www.cryptosys.net/pki/uuid-rfc4122.html

最后的笔记

此外,还有很多第三方软件包。但是,只要您有基本需求,我就不推荐您。确实,赢不了多少,输了很多。作者可能会追求极小的性能,“修复”本不应该修复的问题,而在安全性方面,这是一个冒险的想法。同样,它们可能会引入其他错误或不兼容性。仔细的更新需要时间。

答案 56 :(得分:1)

确定,使用 uuid 程序包,它支持版本1、3、4和5 UUID

yarn add uuid

然后:

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

您也可以使用完全指定的选项来做到这一点:

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'

有关更多信息,请访问npm页面here

答案 57 :(得分:0)

受到 broofa's answer 的启发,我有自己的看法:

以下是使用 crypto.getRandomValues 的加密强度更高的版本。

function uuidv4() {
    const a = crypto.getRandomValues(new Uint16Array(8));
    let i = 0;
    return '00-0-4-1-000'.replace(/[^-]/g, 
            s => (a[i++] + s * 0x10000 >> s).toString(16).padStart(4, '0')
    );
}

console.log(uuidv4());

这是使用 Math.random 的更快版本,使用几乎相同的原理:

function uuidv4() {
    return '00-0-4-1-000'.replace(/[^-]/g,
            s => ((Math.random() + ~~s) * 0x10000 >> s).toString(16).padStart(4, '0')
    );
}

console.log(uuidv4());

答案 58 :(得分:0)

以为我会发布另一种做同样事情的方法。

function guid() {
  var chars = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
  var str = "";
  for(var i=0;i<36;i++) {
    var str = str + ((i == 8 || i == 13 || i == 18 || i == 23) ? "-" : chars[Math.floor(Math.random()*chars.length)]);
  };
  return str;
}

答案 59 :(得分:0)

var guid = createMyGuid();

function createMyGuid()  
{  
   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);  
   });  
}

答案 60 :(得分:0)

生成唯一标识的简单解决方案是使用时间标记并向其添加随机数。我更喜欢在前面添加&#34; uuid - &#34;。

下面的函数将生成以下类型的随机字符串: uuid-14d93eb1b9b4533e6 。一个人不需要生成32个字符随机字符串。在这种情况下,16 char随机字符串足以在javascript中提供唯一的UUID。

var createUUID = function() {
  return"uuid-"+((new Date).getTime().toString(16)+Math.floor(1E7*Math.random()).toString(16));
}

答案 61 :(得分:0)

我们可以使用replace和crypto.getRandomValues获得这样的输出:

xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx

enter image description here

如果要寻找优化解决方案,则必须用数组(32)代替crypto.getRandomValues(new Uint8Array(1))[0]

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

console.log(uuidv4());

要获取此代码:

function uuidv4() {
  let bytes = window.crypto.getRandomValues(new Uint8Array(32));
  const randomBytes = () => (bytes = bytes.slice(1)) && bytes[0];

  return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => 
      (c ^ randomBytes() & 15 >> c / 4).toString(16)
    );
}


for (var i = 0; i < 10; i++)
  console.log(uuidv4());

碰撞:

我们可以像Google Analytics(分析)一样使用并添加时间戳:uuidv4() + "." + (+new Date())

答案 62 :(得分:0)

我找不到使用单个16个八位字节的TypedArray和一个DataView的答案,因此我认为以下用于为每个the RFC生成版本4 UUID的解决方案仍然有效独自在这里:

function uuid4() {
    const ho = (n, p) => n.toString(16).padStart(p, 0); /// Return the hexadecimal text representation of number `n`, padded with zeroes to be of length `p`
    const view = new DataView(new ArrayBuffer(16)); /// Create a view backed by a 16-byte buffer
    crypto.getRandomValues(new Uint8Array(view.buffer)); /// Fill the buffer with random data
    view.setUint8(6, (view.getUint8(6) & 0xf) | 0x40); /// Patch the 6th byte to reflect a version 4 UUID
    view.setUint8(8, (view.getUint8(8) & 0x3f) | 0x80); /// Patch the 8th byte to reflect a variant 1 UUID (version 4 UUIDs are)
    return `${ho(view.getUint32(0), 8)}-${ho(view.getUint16(4), 4)}-${ho(view.getUint16(6), 4)}-${ho(view.getUint16(8), 4)}-${ho(view.getUint32(10), 8)}${ho(view.getUint16(14), 4)}`; /// Compile the canonical textual form from the array data
}

我喜欢它,因为它仅依赖于标准ECMAScript平台可用的功能。

请注意,在编写本文时,getRandomValues还没有为Node.js中的crypto对象实现。但是,它具有randomBytes功能。

答案 63 :(得分:0)

对于科学。我还没有看到有人这样做……它不符合v4,但是可以很容易地更改为。这只是扩展 Uint8Array 类型并使用 crypto.getRandomValues()生成uuid字节值的示例。

class uuid extends Uint8Array {
        constructor() {
            super(16)
            /* not v4, just some random bytes */
            window.crypto.getRandomValues(this)
        }
        toString() {
            let id = new String()
            for (let i = 0; i < this.length; i++) {
                /*convert uint8 to hex string */
                let hex = this[i].toString(16).toUpperCase()

                /*add zero padding*/
                while (hex.length < 2) {
                    hex = String(0).concat(hex)
                }
                id += hex

                /* add dashes */
                if (i == 4 || i == 6 || i == 8 || i == 10 || i == 16){
                    id += '-'
                }
            }
            return id
        }
    }

答案 64 :(得分:0)

这可能对某人有用......

close

https://jsfiddle.net/j0evrdf1/1/

答案 65 :(得分:0)

function randomHex(length) {
    var random_string = '';
    if(!length){
        length = 1;
    }
    for(var i=0; i<length; i+=1){
        random_string += Math.floor(Math.random() * 15).toString(16);
    }
    return random_string;
}

function guid() {
    return randomHex(8);
}

答案 66 :(得分:-2)

我知道这是一个老问题,但几天前我学到了一些新知识,我认为这是“共享”它的好地方:

使用Change.js,您将获得带有一行代码的唯一GUID:

var chance = new Chance();

document.body.innerHTML = chance.guid();
body { font-family: Tahoma }
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Chance.js</title>
</head>
<body>
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet" type="text/css" />
  <script src="http://chancejs.com/chance.min.js"></script>
</body>
</html>

答案 67 :(得分:-2)

我最近一直在使用的那个:

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

答案 68 :(得分:-12)

我知道这个话题很老但是如果你真的想创建一个GUID,你可以在没有直接的javascript的情况下做到这一点。您可以在每次加载时导致页面过期,并在服务器端创建GUID,然后在页面运行时将其填充到javascript变量中。只是一个想法。