在JavaScript中创buildGUID / UUID?
我正在尝试在JavaScript中创build全局唯一的标识符。 我不确定在所有浏览器上有什么例程可用,如何“随机”和播种内置的随机数生成器等等。
GUID / UUID应该至less为32个字符,并且应该保持在ASCII范围内,以避免在传递时遇到麻烦。
曾经有过几次尝试。 问题是:你想要实际的GUID,还是只是看起来像GUID的随机数字? 生成随机数很容易。
function guid() { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); }
但是请注意,这些值不是真正的GUID 。
没有办法在Javascript中生成真正的GUID,因为它们取决于浏览器不公开的本地计算机的属性。 您将需要使用特定于操作系统的服务,如ActiveX: http : //p2p.wrox.com/topicindex/20339.htm
编辑:不正确 – RFC4122允许随机(“版本4”)GUID。 查看其他答案的细节。
注意 :提供的代码片段不遵循RFC4122,它要求版本( 4
)必须集成到生成的输出string中。 如果您需要兼容的GUID,请不要使用此答案 。
使用:
var uuid = guid();
演示:
function guid() { return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } document.getElementById('jsGenId').addEventListener('click', function() { document.getElementById('jsIdResult').value = guid(); })
input { font-family: monospace; }
<button id="jsGenId" type="button">Generate GUID</button> <br> <input id="jsIdResult" type="text" placeholder="Results will be placed here..." readonly size="40"/>
对于符合RFC4122版本4的解决scheme,这种单线 (ish)解决scheme是我能想到的最紧凑的解决scheme。
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())
我真的很喜欢Broofa的答案 ,但不幸的是, Math.random
糟糕实现让我们有了碰撞的机会。
这里有一个类似RFC4122版本4兼容的解决scheme,通过将时间戳的hex部分偏移前13个hex数来解决这个问题。 这样,即使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); }); }
这是一个小提琴来testing。
broofa的回答非常漂亮,的确非常聪明,真的很符合rfc4122标准,可读性强,结构紧凑。 真棒!
但是如果你正在查看这个正则expression式,那么你可能会开始replace()
callback函数, toString()
Math.random()
函数和Math.random()
函数调用(他只使用结果的4位并浪费其余部分)想知道性能。 事实上,joelpt甚至决定用generateQuickGUID
来抛出一般的GUID速度的rfc。
但是,我们能否获得速度和 rfc合规性? 我说是! 我们能保持可读性吗? 呃…并不是真的,但是如果你一直跟随,这很容易。
但首先,我的结果与broofa, guid
(接受的答案)和non-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 that results will vary by browser/cpu.
所以通过我的第六次优化迭代,我超过了12 倍的最受欢迎的答案,超过了9 倍的接受答案, 2-3倍的快速不符合的答案。 而且我仍然符合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); });
所以它用任意的随机hex数字y
来replacex
(除了把rfc规范的前两位强加到10
),而正则expression式不匹配4
字符,所以他不需要处理跟他们。 非常非常漂亮
首先要知道的是,函数调用是昂贵的,正则expression式(虽然他只使用1,但它有32个callback,每个匹配一个,并在每个32callback它调用Math.random()和V的ToString(16))。
性能的第一步是消除RegEx及其callback函数,并使用简单的循环代替。 这意味着我们必须处理-
和4
字符,而broofa没有。 另外请注意,我们可以使用string数组索引来保持他的漂亮的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
,和循环结构(而不是取代callback)得到了我们近3倍的改善!
下一步是在桌面上的一个小的,但在移动设备上有一个体面的差异。 让我们减lessMath.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兼容位的位置,但这并不难。 然后,我们必须创build一个更大的查找表(16×16或256)来存储0x00 – 0xff,并且我们只在e5()函数之外构build一次。
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 }
我尝试了一个e6(),一次处理16位,仍然使用256元素的LUT,并显示优化的收益递减。 虽然迭代较less,但内部逻辑由于处理增加而变得复杂,而且在桌面上执行相同,在移动设备上仅快了约10%。
要应用的最终优化技术 – 展开循环。 既然我们循环了一个固定的次数,我们可以从技术上全部写出来。 我用一个随机variablesr试了一次,我一直在重新分配,而且性能很差。 但是有四个variables先前分配了随机数据,然后使用查找表,并使用适当的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 : UUID.generate()
– UUID.generate()
有趣的是,产生16字节的随机数据是很容易的部分。 整个技巧就是用符合RFC的string格式来expression它,并用16个字节的随机数据,一个展开的循环和查找表来实现。
我希望我的逻辑是正确的 – 在这种单调乏味的工作中犯错很容易。 但是输出对我来说很好。 我希望你喜欢这个疯狂的代码优化!
build议:我的主要目标是展示和教授潜在的优化策略。 其他答案涵盖了重要的主题,如碰撞和真正的随机数字,这对于生成好的UUID很重要。
以下是一些基于RFC 4122第4.4节(从真随机或伪随机数字创buildUUID的algorithm)的代码。
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; }
像XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
格式的string生成器方法最快的GUID。 这不会生成符合标准的GUID。
这个实现的一千万次执行只需要32.5秒,这是我在浏览器中看到的最快(唯一没有循环/迭代的解决scheme)。
function如下简单:
/** * 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(); }
要testing性能,可以运行下面的代码:
console.time('t'); for (var i = 0; i < 10000000; i++) { guid(); }; console.timeEnd('t');
我相信你们大多数人都会明白我在那里做了什么,但也许至less有一个人需要解释:
algorithm:
-
Math.random()
函数返回0到1之间的十进制数字,小数点后面有16位数字(例如0.4363923368509859
)。 - 然后我们把这个数字转换成16位的string(从上面的例子中我们将得到
0.6fb7687f
)。
Math.random().toString(16)
。 - 然后我们切断
0.
前缀(0.6fb7687f
=>6fb7687f
),得到一个长度为八个hex字符的string。
(Math.random().toString(16).substr(2,8)
。 - 有时
Math.random()
函数会返回较短的数字(例如0.4363
),因为最后的零(从上面的例子中,实际上是0.4363000000000000
)。 这就是为什么我追加到这个string"000000000"
(一个有九个零的string),然后使用substr()
函数将其切断,使它精确到九个字符(向右填充零)。 - 加上9个零的原因是由于情况更糟,这是
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种types(或格式):
XXXXXXXX
和-XXXX-XXXX
。 - 现在我正在使用这两种types构buildGUID,以便将GUID与呼叫4个组件组装在一起,如下所示:
XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
。 - 为了
_p8(s)
这两种types,我在一个对创build者函数_p8(s)
添加了一个标志参数,s
参数告诉函数是否添加破折号。 - 最后我们用以下链接构buildGUID:
_p8() + _p8(true) + _p8(true) + _p8()
,并返回它。
链接到我的博客上的这篇文章
请享用! 🙂
这是一个顶级投票的答案 ,与铬的碰撞解决方法的组合:
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); }); };
在jsbin上,如果你想testing它。
以下是来自https://gist.github.com/982883用户的评论,date为2011年10月9日的解决scheme:;
UUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
这实现了与当前最高评分答案相同的目标,但是通过利用强制,recursion和指数表示法减less了50个以上的字节。 对于那些好奇的它是如何工作的,这里是旧版本函数的注释forms:
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 ) }
这是一个完全不兼容但性能非常好的实现,用于生成一个ASCII安全的类GUID唯一标识符。
function generateQuickGuid() { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); }
生成26个[a-z0-9]字符,产生比RFC兼容的GUID更短,更独特的UID。 如果人的可读性很重要的话,可以轻松地添加虚线。
下面是这个函数的使用例子和时间以及这个问题的其他几个答案。 在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');
var uniqueId = Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
如果ID的生成时间超过1毫秒,则它们是100%唯一的。
如果以较短间隔生成两个ID,并且假设随机方法是真正随机的,则这将生成99.99999999999999%的ID,其可能是全局唯一的。
你可以通过增加更多的数字来增加这个数字,但是为了生成100%的唯一ID,你需要使用一个全局计数器。
document.getElementById("unique").innerHTML = Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
<div id="unique"> </div>
Web服务将是有用的。
Google快速find: http : //www.hoskinson.net/GuidGenerator/
不能担保此实现,但SOMEONE必须发布一个真正的GUID生成器。
通过这样的Web服务,您可以开发一个REST Web界面,使用GUID Web服务,并通过AJAX将其提供给浏览器中的JavaScript。
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); }); };
编辑:
重新审视我的项目,使用这个function,不喜欢冗长。 – 但需要适当的随机性。
基于Briguy37的答案和一些按位运算符从缓冲区中提取半字节大小的窗口的版本。
应该遵循RFC Type 4(随机)模式,因为我上次使用Java的UUIDparsing不兼容的uuids时出现了问题。
来自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; }
还有其他方法涉及使用ActiveX控件,但远离这些!
编辑:我认为这是值得指出的没有GUID发电机可以保证唯一的关键(检查维基百科文章 )。 总是有碰撞的机会。 一个GUID只是提供足够大的关键宇宙来减less碰撞的变化几乎为零。
简单的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());
Well, this has a bunch of answers already, but unfortunately there's not a "true" random in the bunch. The version below is an adaptation of broofa's answer, but updated to include a "true" random function that uses crypto libraries where available, and the Alea() function as a 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 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); }); };
From good ol' wikipedia there's a link to a javascript implementation of UUID.
It looks fairly elegant, and could perhaps be improved by salting with a hash of the client's IP address. This hash could perhaps be inserted into the html document server-side for use by the client-side javascript.
UPDATE : The original site has had a shuffle, here is the updated version
JavaScript project on GitHub – LiosK/UUID.html
UUID.js The RFC-compliant UUID generator for JavaScript.
See RFC 4122 http://www.ietf.org/rfc/rfc4122.txt .
Features Generates RFC 4122 compliant UUIDs.
Version 4 UUIDs (UUIDs from random numbers) and version 1 UUIDs (time-based UUIDs) are available.
UUID object allows a variety of access to the UUID including access to the UUID fields.
Low timestamp resolution of JavaScript is compensated by random numbers.
You can use node-uuid ( https://github.com/kelektiv/node-uuid )
Simple, fast generation of RFC4122 UUIDS.
特征:
- Generate RFC4122 version 1 or version 4 UUIDs
- Runs in node.js and browsers.
- Cryptographically strong random # generation on supporting platforms.
- Small footprint (Want something smaller? Check this out! )
Install Using NPM:
npm install uuid
Or Using uuid via browser:
Download Raw File (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Download Raw File (uuid v4): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js
Want even smaller? Check this out: 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'
This create version 4 UUID (created from pseudo random numbers) :
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(''); }
Here is a sample of the UUIDs generated :
682db637-0f31-4847-9cdf-25ba9613a75c 97d19478-3ab2-4aa1-b8cc-a1c3540f54aa 2eed04c9-2692-456d-a0fd-51012f947136
// 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('-');
Adjusted my own UUID/GUID generator with some extras here .
I'm using the following Kybos random number generator to be a bit more cryptographically sound.
Below is my script with the Mash and Kybos methods from baagoe.com excluded.
//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));
The better way:
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 }
Minimized:
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}
For those wanting an rfc4122 version 4 compliant solution with speed considerations (few calls to 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(""); }
The above function should have a decent balance between speed and randomness.
I know, it is an old question. Just for completeness, if your environment is SharePoint, there is a utility function called SP.Guid.newGuid
( msdn link ) which creates a new guid. This function is inside the sp.init.js file. If you rewrite this function (to remove some other dependencies from other private functions), it looks like this:
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; };
It's just a simple AJAX call…
If anyone is still interested, here's my solution.
在服务器端:
[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."); } );
There is a jQuery plugin that handles Guid's nicely @ http://plugins.jquery.com/project/GUID_Helper
jQuery.Guid.Value()
Returns value of internal Guid. If no guid has been specified, returns a new one (value is then stored internally).
jQuery.Guid.New()
Returns a new Guid and sets it's value internally.
jQuery.Guid.Empty()
Returns an empty Guid 00000000-0000-0000-0000-000000000000.
jQuery.Guid.IsEmpty()
Returns boolean. True if empty/undefined/blank/null.
jQuery.Guid.IsValid()
Returns boolean. True valid guid, false if not.
jQuery.Guid.Set()
Retrns Guid. Sets Guid to user specified Guid, if invalid, returns an empty guid.
This one is based on date, and add a random suffix to "ensure" uniqueness. Works well for css identifiers. It always returns something like and is easy to hack:
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; };
I wanted to understand broofa's answer, so I expanded it and added comments:
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); } ); };
It is important that to use well tested code that is maintained by more than 1 contributors instead of whipping your own stuff for this. This is one of the places where you probably want to prefer most stable code than shortest possible clever version that works in X browser but doesn't take in to account idiosyncrasies of Y which would often lead to very hard to investigate bugs than manifests only randomly for some users. Personally I use uuid-js at https://github.com/aurigadl/uuid-js which bower enabled so I can take updates easily.
Weird that no one has mentioned this yet but for completeness, there's a plethora of guid generators on npm I'm willing to bet most of them work in browser too.