如何在JavaScript中创建GUID(全球独特识别器)?GUID/UUID应该至少有32个字符,并且应该保持在ASCII范围内,以避免在通过它们时遇到麻烦。
我不确定在所有浏览器上有哪些习惯,如何“随机”和种植内置的随机号码发电机等。
如何在JavaScript中创建GUID(全球独特识别器)?GUID/UUID应该至少有32个字符,并且应该保持在ASCII范围内,以避免在通过它们时遇到麻烦。
我不确定在所有浏览器上有哪些习惯,如何“随机”和种植内置的随机号码发电机等。
当前回答
这里是一个类似的 RFC4122 版本 4 符合的解决方案,解决了这个问题,通过将第一个 13 个 hex 数字以一个 hex 部分的时光,并一旦被一个 hex 部分的微秒从 pageload. 因此,即使 Math.random 是相同的种子,两个客户将不得不产生 UUID 相同的数量的微秒从 pageload (如果高性能
const generateUUID = () => { let d = new Date().getTime(), d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0; return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { let r = Math.random() * 16; if (d > 0) { r = (d + r) % 16 | 0; d = Math.floor(d / 16); } else { r = (d2 + r) % 16 | 0; d2 = Math.floor(d2 / 16); } return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16); }); }; const onClick = (e) => document.getElementById('uuid').textContent = generateUUID(); document.getElementById('generateUUID').addEventListener('click', onClick); onClick(); #uuid { font-family: monospace; font-size: 1.5em; } <p id="uuid"></p> <button id="generateUUID">Generate UUID</button>
其他回答
下面是使用 crypto.getRandomValues(a)在支持的浏览器(Internet Explorer 11+,iOS 7+,Firefox 21+,Chrome,和Android Chrome)的简单代码。
它避免使用Math.random(),因为这可能会导致碰撞(例如,在 Muxa 实际情况下产生 4000 UUID 的 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 每秒. 它在我的笔记本电脑上在 Chromium 中每秒产生约 10000 uuid() 用 http://jsbin.com/fuwigo/1 来测量性能. 它只使用 8 为 “y” 因为它简化了代码可读性(y 允许为 8, 9, A 或 B)。
下面的版本是布罗法的答案的调整,但更新,包括一个“真实”随机功能,使用加密图书馆在可用的地方,以及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 https://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/
// Johannes Baagøe <baagoe@baagoe.com>, 2010
function Mash() {
var n = 0xefc8249d;
var mash = function(data) {
data = data.toString();
for (var i = 0; i < data.length; i++) {
n += data.charCodeAt(i);
var h = 0.02519603282416938 * n;
n = h >>> 0;
h -= n;
h *= n;
n = h >>> 0;
h -= n;
n += h * 0x100000000; // 2^32
}
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
};
mash.version = 'Mash 0.9';
return mash;
}
// From http://baagoe.com/en/RandomMusings/javascript/
function Alea() {
return (function(args) {
// Johannes Baagøe <baagoe@baagoe.com>, 2010
var s0 = 0;
var s1 = 0;
var s2 = 0;
var c = 1;
if (args.length == 0) {
args = [+new Date()];
}
var mash = Mash();
s0 = mash(' ');
s1 = mash(' ');
s2 = mash(' ');
for (var i = 0; i < args.length; i++) {
s0 -= mash(args[i]);
if (s0 < 0) {
s0 += 1;
}
s1 -= mash(args[i]);
if (s1 < 0) {
s1 += 1;
}
s2 -= mash(args[i]);
if (s2 < 0) {
s2 += 1;
}
}
mash = null;
var random = function() {
var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
s0 = s1;
s1 = s2;
return s2 = t - (c = t | 0);
};
random.uint32 = function() {
return random() * 0x100000000; // 2^32
};
random.fract53 = function() {
return random() +
(random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
};
random.version = 'Alea 0.9';
random.args = args;
return random;
}(Array.prototype.slice.call(arguments)));
};
return Alea();
}
}());
Math.guid = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.trueRandom() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
在这里,你可以找到一个非常小的功能,产生UUID。
最后一个版本是:
function b(
a // Placeholder
){
var cryptoObj = window.crypto || window.msCrypto; // For Internet Explorer 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
)
}
这个是基于日期,并添加一个随机的补充到“保证”的独特性。
它很好地用于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;
};
这里是一个完全不符合但非常有效的实施,以产生一个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 更独特。
这里是这个功能的使用例子和时间表,以及这个问题的其他几个答案。
>>> 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');