生成随机 uuid 的 Javascript 方法

5

我正在尝试构建一个生成随机 UUID 的函数,我在 Stack 上找到了一些东西,需要理解一下这个函数是如何工作的,并使用 TypeScript 创建它:

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

这个es6代码写的好吗?你能帮我理解一下这行代码是如何工作的吗?

var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);

我在那行代码中没有看到es6语法。逗号运算符用于变量声明,三元运算符和位运算符等。 - epascarello
1
这是一种有点过于复杂的方式,用随机十六进制字符替换字符串中的每个“x”。 - Andrey
3个回答

9
你的方法确实生成了一个可以用作uuid的更或多少随机的字符串。但是,它的可读性非常差,换来的是非常简短的代码。此外,它不符合UUIDS的RFC标准。要获取功能更新的解决方案,请查看:https://dev59.com/7HVD5IYBdhLWcg3wDXF3#2117523 。有关UUIDS的更多详细信息,请访问:https://dev59.com/7HVD5IYBdhLWcg3wDXF3#105074 然而,我们特别关注你请求的行,并让我一步一步地尝试解释它。
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);

这行代码定义了两个变量,分别是rv。我们可以很容易地将其拆分为两行。

var r = Math.random() * 16 | 0;
var v = c == 'x' ? r : (r & 0x3 | 0x8);

变量定义 1: (r = Math.random() * 16 | 0;):

  • Math.random() 是一个返回值介于 01 之间的函数。 (包括 0,但不包括 1) [例如:0.36342115]
  • 将该值乘以 16,得到介于 016 之间的结果。 (包括 0,但不包括 16) [例如:5.8147384]
  • 通过使用按位或运算符和零 (| 0),我们基本上对结果进行了向下取整,因为数字被转换为整数。(包括 0 - 包括 15) [例如:5] 不详细解释逻辑运算,与零进行按位或的意思是没有位被更改。但是,由于按位操作是在32位整数上进行的,因此结果会被转换并因此向下取整为整数。为了提高可读性而不会带来太多性能开销,可以使用专门的 floor 函数代替此操作。(https://dev59.com/Lms05IYBdhLWcg3wCNlG#7488075)

除了无符号右移(>>>)以外,所有按位操作都适用于带符号的32位整数。因此,使用按位操作会将浮点数转换为整数。

var r = Math.floor(Math.random() * 16);

变量定义2 (var v = c == 'x' ? r : (r & 0x3 | 0x8);):

如果c等于'x',则v等于r的值,否则v等于r按位与0x3后再或0x8的值。

  • Here a ternary operator is used to keep the required code short for the assignment short.
    var (variableName) = (condition) ? (valueIfConditionIsTrue) : (valueIfConditionIsFalse);
    
    This could be rewritten with a simple if/else-statement.
    var v = "";
    if (c === 'x') { 
        v = r;
    }
    else {
        v = r & 0x3 | 0x8;
    }
    

变量定义 2.1 (var v = r & 0x3 | 0x8):

  • 我们知道r的值可以是0,1,2,3,4,5,6,7,8,9,10,11,12,13,14或者15
  • 通过位与运算符使用0x3和位或运算符使用0x8,结果(v)将具有8,9,10,11中的一个值。
  • 注:由于要替换的字符串中只包含x值,因此您的方法不会发生这种情况。

有关位运算的更多信息,请查看:https://www.w3schools.com/js/js_bitwise.asp

tldr: 只需给我一个在typescript中返回UUID的方法即可。

基于@broofa的最新版本(https://dev59.com/7HVD5IYBdhLWcg3wDXF3#2117523):

uuidv4(): string {  
    // @ts-ignore  
    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>  
        // tslint:disable-next-line:no-bitwise  
        (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)  
    );
}

完整的方法,简化版并用 TypeScript 编写:

generateUniqSerial(): string {  
    return 'xxxx-xxxx-xxx-xxxx'.replace(/[x]/g, (c) => {  
        const r = Math.floor(Math.random() * 16);  
        return r.toString(16);  
  });  
}

此外,需要注意的是,没有理由使用十六进制的 0x30x8,因为它们与 38 完全相同。 - Théophile

0

这里是一个完全不符合规范但非常高效的实现,用于生成类似GUID的ASCII安全唯一标识符。

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

生成26个[a-z0-9]字符,产生的UID比符合RFC标准的GUID更短且更唯一。

注意:任何依赖于Math.random()的UUID生成器都不是强大的,因为它不能提供良好的唯一性保证。


-4

它只是将'xxxx-xxxx-xxx-xxxx'中的每个'x'替换为随机[0123456789abcdef]十六进制字符。这比你实际需要做的uuid多一点。我通常会这样做:

Math.random().toString().replace("0.", "")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接