browser randomuuid - JavaScriptでGUID / UUIDを作成しますか?





15 Answers

RFC4122バージョン4に準拠したソリューションでは、この1ライナー(ish)ソリューションは、私が思い付く最もコンパクトです。

function uuidv4() {
  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(uuidv4())

Update、2015-06-02 :UUIDの一意性は、基礎となる乱数ジェネレータ(RNG)に大きく依存していることに注意してください。 Math.random()は高品質のRNGであること保証されていませんが、上記の解は簡潔さのためにMath.random()を使用しています。 詳細については、Math.random()のAdam Hylandの素晴らしい記事を参照してください。 もっと頑強な解決策を考えるには、uuidモジュール [免責事項:私は作者です]と考えてください。利用できる場合は、より高品質のRNG APIを使用します。

Update、2015-08-26 :サイドノートとして、特定の衝突確率に達する前に生成できるIDの数を決定する方法について説明します。 たとえば、3.26x10 15バージョン4のRFC4122 UUIDでは、100万の衝突の可能性があります。

アップデート、2017-06-28 :Chrome、Firefox、SafariのMath.random PRNGの品質についてChrome開発者が優れた記事を投稿しました。 tl; dr - 2015年末の時点では「かなり良い」と言われていますが、暗号の品質はありません。 この問題に対処するために、ここではES6、 crypto API、および少しのJSウィザードを使用する上記のソリューションの最新バージョンがあります。 私は信用できません

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  )
}

console.log(uuidv4());

() regex newguid

JavaScriptでグローバルに一意の識別子を作成しようとしています。 私はどのようなルーチンがすべてのブラウザで利用可能であるか、どのように "ランダムに"組み込みの乱数ジェネレータがシードされているかなどはわかりません。

GUID / UUIDは32文字以上でなければならず、渡す際のトラブルを避けるためにASCII範囲にとどまるべきです。




ブローファの答えはかなり滑らかです、実際には印象的な賢さ、本当に... rfc4122準拠、やや可読性、コンパクト。 驚くばかり!

しかし、あなたがその正規表現を見ているなら、多くのreplace()コールバック、 toString()Math.random()関数呼び出し(ここでは4ビットの結果しか使用せず残りを無駄にしています)を開始することもできますパフォーマンスについて不思議に思う 実際、joelptはgenerateQuickGUIDを使用して一般的なGUID速度のRFCを捨てることに決めました。

しかし、スピード RFC準拠を得ることができますか? 私は言う、はい! 読みやすさを維持できますか? まあ...実際はそうですが、あなたが一緒に従うならば簡単です。

しかし、まず、ブローファ、 guid (受け入れられた回答)、および非rfc準拠のgenerateQuickGuidと比較した私の結果:

                  Desktop   Android
           broofa: 1617ms   12869ms
               e1:  636ms    5778ms
               e2:  606ms    4754ms
               e3:  364ms    3003ms
               e4:  329ms    2015ms
               e5:  147ms    1156ms
               e6:  146ms    1035ms
               e7:  105ms     726ms
             guid:  962ms   10762ms
generateQuickGuid:  292ms    2961ms
  - Note: 500k iterations, results will vary by browser/cpu.

だから私の6回目の最適化では、最も一般的な回答を12倍以上、受け入れた回答を9倍以上、速い順応しない回答を2〜3倍で打ちました 。 私はまだrfc4122に準拠しています。

どのように興味がありますか? 私はhttp://jsfiddle.net/jcward/7hyaC/3/http://jsfiddle.net/jcward/7hyaC/3/完全なソースを載せました

説明のために、ブローファのコードから始めましょう:

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

したがって、 xをランダムな16進数字で置き換え、 yをランダムなデータで置き換えます(ただし、RFC仕様では上位2ビットを10強制します)。正規表現は4文字に一致しないので、処理する必要はありませんそれらと一緒に。 非常に、非常に滑らか。

最初に知っておくべきことは、正規表現と同じように関数呼び出しが高価であることです(ただし、彼は1つしか使用しませんが、32個のコールバック、各一致のために1つ、Math.random()とvを呼び出す32個のコールバック) toString(16))。

パフォーマンスへの第一歩は、RegExとそのコールバック関数を削除し、代わりに単純なループを使用することです。 これは、ブローファがしなかったのに対し、 -4文字を扱わなければならないことを意味します。 また、String Arrayの索引付けを使用して、洗練されたStringテンプレート・アーキテクチャーを保つこともできます。

function e1() {
  var u='',i=0;
  while(i++<36) {
    var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);
    u+=(c=='-'||c=='4')?c:v.toString(16)
  }
  return u;
}

基本的に、同じ内部ロジックは、 -または4をチェックし、 replace()コールバックの代わりにwhileループを使うと、ほぼ3倍の改善が得られます!

次のステップはデスクトップ上の小さなものですが、モバイルではまったく違いがあります。 より少ない数のMath.random()呼び出しを行い、それらの87%をそれぞれの反復からシフトアウトされるランダムなバッファで投げるのではなく、すべてのランダムなビットを利用しましょう。 テンプレート定義をループの外に移動してみましょう。

function e2() {
  var u='',m='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',i=0,rb=Math.random()*0xffffffff|0;
  while(i++<36) {
    var c=m[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
    u+=(c=='-'||c=='4')?c:v.toString(16);rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
  }
  return u
}

これにより、プラットフォームに応じて10〜30%節約できます。 悪くない。 しかし、次の大きなステップは、toString関数の呼び出しをすべて最適化の古典であるルックアップ・テーブルで取り除きます。 シンプルな16要素ルックアップテーブルは、はるかに短い時間でtoString(16)のジョブを実行します:

function e3() {
  var h='0123456789abcdef';
  var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
  /* same as e4() below */
}
function e4() {
  var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
  var k=['x','x','x','x','x','x','x','x','-','x','x','x','x','-','4','x','x','x','-','y','x','x','x','-','x','x','x','x','x','x','x','x','x','x','x','x'];
  var u='',i=0,rb=Math.random()*0xffffffff|0;
  while(i++<36) {
    var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
    u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
  }
  return u
}

次の最適化はもう一つの古典です。 各ループ反復では4ビットの出力しか処理していないので、ループの数を半分に減らし、反復ごとに8ビットを処理してみましょう。 RFCに準拠したビット位置を処理する必要があるので、これは難しいですが、それほど難しいことではありません。 次に、0x00〜0xffを格納するために、より大きなルックアップテーブル(16x16または256)を作成しなければならず、e5()関数の外部で1回しか構築しません。

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e5() {
  var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];
  var u='',i=0,rb=Math.random()*0xffffffff|0;
  while(i++<20) {
    var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));
    u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8
  }
  return u
}

私は一度に16ビットを処理するe6()を試しましたが、それでも256要素のLUTを使用していました。最適化のリターンが小さくなっています。 反復回数は少なくなっていますが、内部ロジックは処理が複雑になると複雑になり、デスクトップでも同じ処理を行い、モバイルでは10%しか高速化しませんでした。

適用するための最終的な最適化テクニック - ループを展開します。 私たちは一定回数ループしているので、技術的にはすべて手作業で書くことができます。 私はこれを一度ランダム変数rを使って再試行しました。 しかし、4つの変数にランダムなデータが割り当てられ、ルックアップテーブルを使用し、適切なRFCビットを適用することで、このバージョンはすべてを吸います。

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e7()
{
  var d0 = Math.random()*0xffffffff|0;
  var d1 = Math.random()*0xffffffff|0;
  var d2 = Math.random()*0xffffffff|0;
  var d3 = Math.random()*0xffffffff|0;
  return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
    lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
    lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
    lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
}

Modualized: http://jcward.com/UUID.js ://jcward.com/UUID.js - UUID.generate()

面白いのは、16バイトのランダムデータを生成するのが簡単なことです。 トリック全体は、RFC準拠のString形式で表現されています.16バイトのランダムデータ、展開されていないループ、ルックアップテーブルを使用しています。

私の論理が正しいことを願っています。このような退屈なビットワークを間違えてしまうのはとても簡単です。 しかし、出力は私によく見える。 私はあなたがコード最適化を通してこの狂った乗り物を楽しんでくれたことを願っています

私の第一の目標は、潜在的な最適化戦略を示し、教えることでした。 その他の回答には、衝突や本当に乱数などの重要なトピックが含まれています。これらは良好なUUIDを生成する上で重要です。




XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXという形式の最速GUIDストリングジェネレータメソッド。 標準に準拠したGUIDは生成されません。

この実装の実行回数は1000万回で32.5秒で、これはブラウザで見た中で最も速い(ループ/反復なしの唯一の解決策)。

この関数は次のように簡単です:

/**
 * Generates a GUID string.
 * @returns {String} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser (slavik@meltser.info).
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

パフォーマンスをテストするには、次のコードを実行します。

console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    guid(); 
};
console.timeEnd('t');

私はあなたのほとんどが私がそこで何をしたのか理解するだろうと確信していますが、多分説明が必要な人が少なくとも一人はいます:

アルゴリズム:

  • Math.random()関数は、小数点以下16桁の0から1の間の10進数を返します(たとえば、 0.4363923368509859 )。
  • 次に、この数値を基数16の文字列に変換します(上記の例では、 0.6fb7687fが得られ0.6fb7687f )。
    Math.random().toString(16)
  • その後、接頭辞( 0.6fb7687f => 6fb7687f )を6fb7687f 、8 6fb7687f 16進数の文字列を取得します。
    (Math.random().toString(16).substr(2,8)
  • 場合によっては、 Math.random()関数は最後のゼロ(実際には0.4363000000000000 )から短い数値(たとえば0.4363 )を返します。 だから、私はこの文字列"000000000" (9個の0を持つ文字列)を追加して、 substr()関数で切り捨てて9個の文字を正確に(右にゼロを埋めてsubstr()作る。
  • 正確に9つのゼロを追加する理由は、 Math.random()関数が正確に0または1(それぞれのMath.random() ^ 16の確率Math.random()を返す悪いケースのシナリオのためです。 そのため、9つのゼロ( "0"+"000000000"または"1"+"000000000" )を追加して、8文字の長さの2番目のインデックス(3番目の文字)から切り捨てる必要がありました。 それ以外の場合は、ゼロを追加しても結果が損なわれることはありません。
    Math.random().toString(16)+"000000000").substr(2,8)

アセンブリ:

  • GUIDの形式はXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXです。
  • 私はGUIDを4つの部分に分けました。各部分は2つのタイプ(または形式): XXXXXXXX-XXXX-XXXX分けられました。
  • 今度は、これら2つのタイプを使用してGUIDを構築して、次のように4つの呼び出しでGUIDをアセンブルします-XXXX-XXXX -XXXX-XXXX XXXXXXXX
  • これらの2つのタイプを_p8(s)するために、私はペア作成者関数_p8(s)にフラグ・パラメーターを追加しました_p8(s)パラメーターは、ダッシュを追加するかどうかを関数に指示します。
  • 最終的に_p8() + _p8(true) + _p8(true) + _p8()チェーンを使用してGUIDを構築し、それを返します。

私のブログにこの記事へのリンク

楽しい! :-)




一番上の投票回答とChromeの衝突の回避策の組み合わせは次のとおりです。

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // https://.com/questions/6906916/collisions-when-generating-uuids-in-javascript
        var 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://.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
        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);
        });
    };

jsbinでテストしたい場合。




ここには完全に準拠していないが、ASCII安全なGUIDのようなユニークな識別子を生成するための非常に実行可能な実装があります。

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

26 [a-z0-9]文字を生成し、RFCに準拠したGUIDよりも短くユニークなUIDを生成します。 人間の可読性が重要な場合は、ダッシュを簡単に追加できます。

ここでは、この関数の使用例とタイミングと、この質問のその他の回答のいくつかを示します。 タイミングはChrome m25の下でそれぞれ1千万回繰り返し実行されました。

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



Webサービスが便利です。

クイックGoogleが見つかりました: http://www.hoskinson.net/GuidGenerator/ : http://www.hoskinson.net/GuidGenerator/

この実装を保証することはできませんが、誰かがbonafide GUIDジェネレータを公開する必要があります。

このようなWebサービスを使用すると、GUID Webサービスを使用するREST Webインターフェイスを開発し、AJAXを介してブラウザでjavascriptを実行することができます。




このスレッドのベストアンサーを組み合わせた単純なJavaScriptモジュール。

var crypto = window.crypto || window.msCrypto || null; // IE11 fix

var Guid = Guid || (function() {

  var EMPTY = '00000000-0000-0000-0000-000000000000';

  var _padLeft = function(paddingString, width, replacementChar) {
    return paddingString.length >= width ? paddingString : _padLeft(replacementChar + paddingString, width, replacementChar || ' ');
  };

  var _s4 = function(number) {
    var hexadecimalResult = number.toString(16);
    return _padLeft(hexadecimalResult, 4, '0');
  };

  var _cryptoGuid = function() {
    var buffer = new window.Uint16Array(8);
    window.crypto.getRandomValues(buffer);
    return [_s4(buffer[0]) + _s4(buffer[1]), _s4(buffer[2]), _s4(buffer[3]), _s4(buffer[4]), _s4(buffer[5]) + _s4(buffer[6]) + _s4(buffer[7])].join('-');
  };

  var _guid = function() {
    var currentDateMilliseconds = new Date().getTime();
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(currentChar) {
      var randomChar = (currentDateMilliseconds + Math.random() * 16) % 16 | 0;
      currentDateMilliseconds = Math.floor(currentDateMilliseconds / 16);
      return (currentChar === 'x' ? randomChar : (randomChar & 0x7 | 0x8)).toString(16);
    });
  };

  var create = function() {
    var hasCrypto = crypto != 'undefined' && crypto !== null,
      hasRandomValues = typeof(window.crypto.getRandomValues) != 'undefined';
    return (hasCrypto && hasRandomValues) ? _cryptoGuid() : _guid();
  };

  return {
    newGuid: create,
    empty: EMPTY
  };
})();

// DEMO: Create and show GUID
console.log(Guid.newGuid());

使用法:

Guid.newGuid()

"c6c2d12f-d76b-5739-e551-07e6de5b0807"

Guid.empty

"00000000-0000-0000-0000-000000000000"




古き良きウィキペディア UUIDのjavascriptの実装へのリンクがあります。

それはかなり優雅に見え、おそらくクライアントのIPアドレスのハッシュで塩をかけることで改善することができます。このハッシュは、おそらくクライアントサイドのJavaScriptで使用するためにhtmlドキュメントのサーバー側に挿入することができます。

更新:元のサイトにシャッフルがありました。ここには更新版があります




GitHubのJavaScriptプロジェクト - https://github.com/LiosK/UUID.js

UUID.js JavaScript対応のRFC準拠のUUIDジェネレータ。

RFC 4122 ietf.org/rfc/rfc4122.txt参照してietf.org/rfc/rfc4122.txt

機能RFC 4122準拠のUUIDを生成します。

バージョン4のUUID(乱数によるUUID)とバージョン1のUUID(時間ベースのUUID)が利用可能です。

UUIDオブジェクトは、UUIDフィールドへのアクセスを含む、UUIDへの様々なアクセスを可能にする。

JavaScriptのタイムスタンプの分解能は、乱数によって補償されます。




  // 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 values
  var 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('-');



より良い方法:

function(
  a,b                // placeholders
){
  for(               // loop :)
      b=a='';        // b - result , a - numeric variable
      a++<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
              ?      // genetate a random number from 0 to 15
           8^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(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}



それは単なるAJAX呼び出しです...

誰かがまだ興味を持っているなら、ここに私の解決策があります。

サーバー側:

[WebMethod()]
public static string GenerateGuid()
{
    return Guid.NewGuid().ToString();
}

クライアント側:

var myNewGuid = null;
PageMethods.GenerateGuid(
    function(result, userContext, methodName)
    {
        myNewGuid = result;
    },
    function()
    {
        alert("WebService call failed.");
    }
);



私は知っている、それは古い質問です。完全性のために、環境がSharePointの場合、新しいGUIDを作成するユーティリティ関数SP.Guid.newGuidmsdn link)があります。この関数はsp.init.jsファイル内にあります。この関数を書き直すと(他のプライベート関数から他の依存関係を削除するために)、次のようになります:

var newGuid = function () {
    var result = '';
    var hexcodes = "0123456789abcdef".split("");

    for (var index = 0; index < 32; index++) {
        var value = Math.floor(Math.random() * 16);

        switch (index) {
        case 8:
            result += '-';
            break;
        case 12:
            value = 4;
            result += '-';
            break;
        case 16:
            value = value & 3 | 8;
            result += '-';
            break;
        case 20:
            result += '-';
            break;
        }
        result += hexcodes[value];
    }
    return result;
};



ES6サンプル

const guid=()=> {
  const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
  return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}



誰もこれをまだ言及していないけれど、完全性のために、npmguidジェネレータがたくさんあります。私はそれらのほとんどがブラウザで動作すると確信しています。




Related