5

I'm trying to build a function to generate a random uuid, I found some thing on stack and I need to understand a little bit how that function work to create it with 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);
    });
  }

is that writen good in es6 and can you help to understand how that line works :

var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
ggorlen
  • 44,755
  • 7
  • 76
  • 106
547n00n
  • 1,356
  • 6
  • 30
  • 55

3 Answers3

9

It is true that your method generates a more or less random string which could be used as a uuid. However, its readability is very bad, in exchange for very short code. Additonally it does not stick to the RFC standards for UUIDS. For an updated solution of your function check out: https://stackoverflow.com/a/2117523/8524465 and for more details on UUIDS: https://stackoverflow.com/a/105074/8524465

However, let's focus especially on your requested line and let me try to explain it step by step.

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

This line defines 2 variables, namely r and v. We can easily split this into 2 lines.

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

Variable Definition 1: (r = Math.random() * 16 | 0;):

  • Math.random() is a function that returns a value between 0 and 1. (0 inclusive - 1 exclusive) [E.g: 0.36342115]
  • By multipling the value with 16, the result is between 0 and 16. (0 inclusive - 16 exclusive) [E.g: 5.8147384]
  • By using the bitwise OR-operator with zero (| 0), we basically floor the result, since the number ist cast to an integer. (0 inclusive - 15 inclusive) [E.g: 5] Without going into too much detail of logic operations, a bitwise or with zero means that no bits are changed. However, since bitwise operations work on 32-bit integers the result is cast and hence floored to an integer. Without too much performance overhead we can replace this action with a dedicated floor function to improve readability. (https://stackoverflow.com/a/7488075/8524465)

All bitwise operations except unsigned right shift, >>>, work on signed 32-bit integers. So using bitwise operations will convert a float to an integer.

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

Variable Definition 2 (var v = c == 'x' ? r : (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;
    }
    

Variable Definition 2.1 (var v = r & 0x3 | 0x8):

  • We know that r has a value of either 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,or 15.
  • By using the bitwise AND-operator with 0x3 and the bitwise OR-operator with 0x8, the result (v) will have a value of either 8,9,10,11.
  • Sidenote: this case will never happen in your method since your string that is replaced only contains the x values.

For more information on bitwise operations check out: https://www.w3schools.com/js/js_bitwise.asp

tldr: Just give me a method that returns a UUID in typescript.

Using the @broofa 's newest version (https://stackoverflow.com/a/2117523/8524465) as base:

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

For completion: your method, simplified and written in typescript:

generateUniqSerial(): string {  
    return 'xxxx-xxxx-xxx-xxxx'.replace(/[x]/g, (c) => {  
        const r = Math.floor(Math.random() * 16);  
        return r.toString(16);  
  });  
}
Daniel Metzner
  • 101
  • 2
  • 4
  • To add to this, note that there's no reason to use hexadecimal `0x3` or `0x8`, since they're exactly the same as `3` and `8`. – Théophile May 11 '22 at 13:24
0

Here is a totally non-compliant but very performant implementation to generate an ASCII-safe GUID-like unique identifier.

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

Generates 26 [a-z0-9] characters, yielding a UID that is both shorter and more unique than RFC compliant GUIDs.

Note: Any UUID generator that relies on Math.random() is not strongly, because it does not provide good uniqueness guarantees.

Efrat Ifergan
  • 184
  • 1
  • 5
-4

It just replaces every 'x' in 'xxxx-xxxx-xxx-xxxx' with a random [0123456789abcdef] hex character. A little bit more than you really need to do for a uuid. I usually do:

Math.random().toString().replace("0.", "")
Aaron Plocharczyk
  • 2,776
  • 2
  • 7
  • 15