🐙

Javascript で UUID (v4) を生成する

2021/01/08に公開

UUIDにはいくつかの変種やバージョンがありますが、その中でもRFC 4122の中で定義されているバージョン4は単純に乱数で生成するという非常にシンプルな仕組みになっています。

自前で作るのも簡単なので、実際にJavascriptでも書いてみました。

実際に作ってみる

その1
class UUID {

  static #uuidIte = ( function* () {

    const HEXOCTETS = Object.freeze( [ ...Array( 0x100 ) ].map( ( e, i ) => i.toString( 0x10 ).padStart( 2, "0" ).toUpperCase() ) );
    const VARSION = 0x40;
    const VARIANT = 0x80;

    for (;;) {

      const bytes = crypto.getRandomValues( new Uint8Array( 16 ) );
      yield "" +
        HEXOCTETS[ bytes[ 0 ] ] +
        HEXOCTETS[ bytes[ 1 ] ] +
        HEXOCTETS[ bytes[ 2 ] ] +
        HEXOCTETS[ bytes[ 3 ] ] + "-" +
        HEXOCTETS[ bytes[ 4 ] ] +
        HEXOCTETS[ bytes[ 5 ] ] + "-" +
        HEXOCTETS[ bytes[ 6 ] & 0x0f | VARSION ] +
        HEXOCTETS[ bytes[ 7 ] ] + "-" +
        HEXOCTETS[ bytes[ 8 ] & 0x3f | VARIANT ] +
        HEXOCTETS[ bytes[ 9 ] ] + "-" +
        HEXOCTETS[ bytes[ 10 ] ] +
        HEXOCTETS[ bytes[ 11 ] ] +
        HEXOCTETS[ bytes[ 12 ] ] +
        HEXOCTETS[ bytes[ 13 ] ] +
        HEXOCTETS[ bytes[ 14 ] ] +
        HEXOCTETS[ bytes[ 15 ] ];

    }

  } )();

  static randomUUID() {

    return this.#uuidIte.next().value;

  }

}

console.log( UUID.randomUUID() ); //e.g. 16E3908E-96DF-468E-B148-90A11814615F

ついでに、Node.jsでは組み込みにcryptoがないようなので、Math.random()を使った実装も載せます。

その2(crypto未使用)
class UUID {

  static #uuidIte = ( function* () {

    const HEXOCTETS = Object.freeze( [ ...Array( 0x100 ) ].map( ( e, i ) => i.toString( 0x10 ).padStart( 2, "0" ).toUpperCase() ) );
    const VARSION = 0x40;
    const VARIANT = 0x80;
    const bytes = new Uint8Array( 16 );
    const rand = new Uint32Array( bytes.buffer );

    for (;;) {

      for ( let i = 0; i < rand.length; i++ ) {
        rand[ i ] = Math.random() * 0x100000000 >>> 0;
      }

      yield "" +
        HEXOCTETS[ bytes[ 0 ] ] +
        HEXOCTETS[ bytes[ 1 ] ] +
        HEXOCTETS[ bytes[ 2 ] ] +
        HEXOCTETS[ bytes[ 3 ] ] + "-" +
        HEXOCTETS[ bytes[ 4 ] ] +
        HEXOCTETS[ bytes[ 5 ] ] + "-" +
        HEXOCTETS[ bytes[ 6 ] & 0x0f | VARSION ] +
        HEXOCTETS[ bytes[ 7 ] ] + "-" +
        HEXOCTETS[ bytes[ 8 ] & 0x3f | VARIANT ] +
        HEXOCTETS[ bytes[ 9 ] ] + "-" +
        HEXOCTETS[ bytes[ 10 ] ] +
        HEXOCTETS[ bytes[ 11 ] ] +
        HEXOCTETS[ bytes[ 12 ] ] +
        HEXOCTETS[ bytes[ 13 ] ] +
        HEXOCTETS[ bytes[ 14 ] ] +
        HEXOCTETS[ bytes[ 15 ] ];

    }

  } )();

  static randomUUID() {

    return this.#uuidIte.next().value;

  }

}

console.log( UUID.randomUUID() ); //e.g. 16E3908E-96DF-468E-B148-90A11814615F

以上!
分散型でかなり高速に生成できるのに一意な値として使えるのは不思議な感じがします。

Discussion