// 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 valuesvar 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('-');
UUIDv4 =
function b(a // placeholder){return a // if the placeholder was passed, return? ( // a random number from 0 to 15a ^ // 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 withb // random hex digits)}
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解析不兼容的UUID时使用了问题。
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-javascriptvar 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#2117523return '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);});};
function(a, b // Placeholders){for( // Loop :)b = a = ''; // b - result , a - numeric variablea++ < 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,? // generate a random number from 0 to 158^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 broofa() {return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);return v.toString(16);});}
console.log(broofa())
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);});};
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)
function b(a // Placeholder){var cryptoObj = window.crypto || window.msCrypto; // For Internet Explorer 11return a // If the placeholder was passed, return? ( // a random number from 0 to 15a ^ // 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 withb // random hex digits)}
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}}
const 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 data = crypto.getRandomValues(new Uint8Array(16)); /// Fill the buffer with random datadata[6] = (data[6] & 0xf) | 0x40; /// Patch the 6th byte to reflect a version 4 UUIDdata[8] = (data[8] & 0x3f) | 0x80; /// Patch the 8th byte to reflect a variant 1 UUID (version 4 UUIDs are)const view = new DataView(data.buffer); /// Create a view backed by a 16-byte bufferreturn `${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};
// 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"
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);});}
/** uuid-timestamp (emitter)* UUID v4 based on timestamp** Created by tarkh* tarkh.com (C) 2020*/const uuidEmit = () => {// Get now timeconst n = Date.now();// Generate randomconst r = Math.random();// Stringify now time and generate additional random numberconst s = String(n) + String(~~(r*9e4)+1e4);// Form UUID and return itreturn `${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 UUIDsconsole.log(`${uuidEmit()}${uuidEmit()}${uuidEmit()}${uuidEmit()}${uuidEmit()}`);
/** uuid-timestamp (parser)* UUID v4 based on timestamp** Created by tarkh* tarkh.com (C) 2020*/const uuidParse = (uuid) => {// Get current timestamp string lengthlet tl = String(Date.now()).length;// Strip out timestamp from UUIDlet 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 emittedconst time = uuidParse('15970688-7109-4530-8114-887109530114');
// Covert timestamp to date and print itconsole.log(new Date(time).toUTCString());
function uuid4() {let array = new Uint8Array(16)crypto.randomFillSync(array)
// Manipulate the 9th bytearray[8] &= 0b00111111 // Clear the first two bitsarray[8] |= 0b10000000 // Set the first two bits to 10
// Manipulate the 7th bytearray[6] &= 0b00001111 // Clear the first four bitsarray[6] |= 0b01000000 // Set the 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 a leading zero, if needed)}
浏览器版本
只有第二行是不同的。
function uuid4() {let array = new Uint8Array(16)crypto.getRandomValues(array)
// Manipulate the 9th bytearray[8] &= 0b00111111 // Clear the first two bitsarray[8] |= 0b10000000 // Set the first two bits to 10
// Manipulate the 7th bytearray[6] &= 0b00001111 // Clear the first four bitsarray[6] |= 0b01000000 // Set the 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 a leading zero, if needed)}
currentNanoseconds = () => {return nodeMode ? process.hrtime.bigint() : BigInt(Date.now() * 1000000);}
nodeFindMacAddress = () => {// Extract MAC addressconst 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 testinglet currentTime = null; // Holds the last value of Date.now(), used as a base for generating the UUIDlet timePart = null; // Part of the UUID generated from Date.now()let counter = 0; // Used for counting records created at certain millisecondlet 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;}