衫裤跑路
2008-09-19 20:01
采纳率: 0%
浏览 563
已采纳

在 JavaScript 中创建 GUID / UUID?

I'm trying to create globally-unique identifiers in JavaScript. I'm not sure what routines are available on all browsers, how "random" and seeded the built-in random number generator is, etc..

The GUID / UUID should be at least 32 characters and should stay in the ASCII range to avoid trouble when passing them around.

转载于:https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

30条回答 默认 最新

  • 零零乙 2014-04-04 07:13
    已采纳

    There have been a couple attempts at this. The question is: do you want actual GUIDs, or just random numbers that look like GUIDs? It's easy enough to generate random numbers.

    function guid() {
      function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
          .toString(16)
          .substring(1);
      }
      return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
    }
    

    However, note that such values are not genuine GUIDs.

    Note: the provided code snippet does not follow RFC4122 which requires that the version (4) has to be integrated into the generated output string. Do not use this answer if you need compliant GUIDs.

    Use:

    var uuid = guid();
    

    Demo:

    function guid() {
      return "ss-s-s-s-sss".replace(/s/g, s4);
    }
    
    function s4() {
      return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
    }
    
    document.getElementById('jsGenId').addEventListener('click', function() {
      document.getElementById('jsIdResult').value = guid();
    })
    input { font-family: monospace; }
    <button id="jsGenId" type="button">Generate GUID</button>
    <br>
    <input id="jsIdResult" type="text" placeholder="Results will be placed here..." readonly size="40"/>

    </div>
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • local-host 2014-04-04 07:13

    Here's a solution dated Oct. 9, 2011 from a comment by user jed at https://gist.github.com/982883:

    UUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
    

    This accomplishes the same goal as the current highest-rated answer, but in 50+ fewer bytes by exploiting coercion, recursion, and exponential notation. For those curious how it works, here's the annotated form of an older version of the function:

    UUIDv4 =
    
    function b(
      a // placeholder
    ){
      return a // if the placeholder was passed, return
        ? ( // a random number from 0 to 15
          a ^ // 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 with
            b // random hex digits
          )
    }
    
    评论
    解决 无用
    打赏 举报
  • ~Onlooker 2014-04-04 07:13

    Fastest GUID like string generator method in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. This does not generate standard-compliant GUID.

    Ten million executions of this implementation take just 32.5 seconds, which is the fastest I've ever seen in a browser (the only solution without loops/iterations).

    The function is as simple as:

    /**
     * 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();
    }
    

    To test the performance, you can run this code:

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

    I'm sure most of you will understand what I did there, but maybe there is at least one person that will need an explanation:

    The algorithm:

    • The Math.random() function returns a decimal number between 0 and 1 with 16 digits after the decimal fraction point (for example 0.4363923368509859).
    • Then we take this number and convert it to a string with base 16 (from the example above we'll get 0.6fb7687f).
      Math.random().toString(16).
    • Then we cut off the 0. prefix (0.6fb7687f => 6fb7687f) and get a string with eight hexadecimal characters long.
      (Math.random().toString(16).substr(2,8).
    • Sometimes the Math.random() function will return shorter number (for example 0.4363), due to zeros at the end (from the example above, actually the number is 0.4363000000000000). That's why I'm appending to this string "000000000" (a string with nine zeros) and then cutting it off with substr() function to make it nine characters exactly (filling zeros to the right).
    • The reason for adding exactly nine zeros is because of the worse case scenario, which is when the Math.random() function will return exactly 0 or 1 (probability of 1/10^16 for each one of them). That's why we needed to add nine zeros to it ("0"+"000000000" or "1"+"000000000"), and then cutting it off from the second index (3rd character) with a length of eight characters. For the rest of the cases, the addition of zeros will not harm the result because it is cutting it off anyway.
      Math.random().toString(16)+"000000000").substr(2,8).

    The assembly:

    • The GUID is in the following format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
    • I divided the GUID into 4 pieces, each piece divided into 2 types (or formats): XXXXXXXX and -XXXX-XXXX.
    • Now I'm building the GUID using these 2 types to assemble the GUID with call 4 pieces, as follows: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
    • To differ between these two types, I added a flag parameter to a pair creator function _p8(s), the s parameter tells the function whether to add dashes or not.
    • Eventually we build the GUID with the following chaining: _p8() + _p8(true) + _p8(true) + _p8(), and return it.

    Link to this post on my blog

    Enjoy! :-)

    评论
    解决 无用
    打赏 举报
  • elliott.david 2014-04-04 07:13

    A web service would be useful.

    Quick Google found: http://www.hoskinson.net/GuidGenerator/

    Can't vouch for this implementation, but SOMEONE must publish a bonafide GUID generator.

    With such a web service, you could develop a REST web interface that consumes the GUID web service, and serves it through AJAX to javascript in a browser.

    评论
    解决 无用
    打赏 举报
  • 三生石@ 2014-04-04 07:13
      // 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('-');
    
    评论
    解决 无用
    打赏 举报
  • 7*4 2014-04-04 07:13

    Adjusted my own UUID/GUID generator with some extras here.

    I'm using the following Kybos random number generator to be a bit more cryptographically sound.

    Below is my script with the Mash and Kybos methods from baagoe.com excluded.

    //UUID/Guid Generator
    // use: UUID.create() or UUID.createSequential()
    // convenience:  UUID.empty, UUID.tryParse(string)
    (function(w){
      // From http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <baagoe@baagoe.com>, 2010
      //function Mash() {...};
    
      // From http://baagoe.com/en/RandomMusings/javascript/
      //function Kybos() {...};
    
      var rnd = Kybos();
    
      //UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
      var UUID = {
        "empty": "00000000-0000-0000-0000-000000000000"
        ,"parse": function(input) {
          var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
          if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
            return ret;
          else
            throw new Error("Unable to parse UUID");
        }
        ,"createSequential": function() {
          var ret = new Date().valueOf().toString(16).replace("-","")
          for (;ret.length < 12; ret = "0" + ret);
          ret = ret.substr(ret.length-12,12); //only least significant part
          for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
          return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
        }
        ,"create": function() {
          var ret = "";
          for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
          return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
        }
        ,"random": function() {
          return rnd();
        }
        ,"tryParse": function(input) {
          try {
            return UUID.parse(input);
          } catch(ex) {
            return UUID.empty;
          }
        }
      };
      UUID["new"] = UUID.create;
    
      w.UUID = w.Guid = UUID;
    }(window || this));
    评论
    解决 无用
    打赏 举报
  • 笑故挽风 2014-04-04 07:13

    Here is a combination of the top voted answer, with a workaround for Chrome's collisions:

    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-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://stackoverflow.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);
            });
        };
    

    On jsbin if you want to test it.

    评论
    解决 无用
    打赏 举报
  • 旧行李 2014-04-04 07:13
    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);
        });
    };
    

    EDIT:

    Revisited my project that was using this function and disliked the verbosity. - But needed proper randomness.

    A version based on Briguy37's answer and some bitwise operators to extract nibble sized windows from the buffer.

    Should adhere to the RFC Type 4 (random) schema, since I had Problems last time parsing non-compliant uuids with Java's UUID.

    评论
    解决 无用
    打赏 举报
  • lrony* 2014-04-04 07:13

    The better way:

    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
     }
    

    Minimized:

    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}
    
    评论
    解决 无用
    打赏 举报
  • 零零乙 2014-04-04 07:13

    This one is based on date, and add a random suffix to "ensure" uniqueness. Works well for css identifiers. It always returns something like and is easy to hack:

    uid-139410573297741

    var getUniqueId = function (prefix) {
                var d = new Date().getTime();
                d += (parseInt(Math.random() * 100)).toString();
                if (undefined === prefix) {
                    prefix = 'uid-';
                }
                d = prefix + d;
                return d;
            };
    
    评论
    解决 无用
    打赏 举报
  • lrony* 2014-04-04 07:13

    Simple JavaScript module as a combination of best answers in this thread.

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

    Usage:

    Guid.newGuid()

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

    Guid.empty

    "00000000-0000-0000-0000-000000000000"

    </div>
    
    评论
    解决 无用
    打赏 举报
  • 七度&光 2014-04-04 07:13

    From good ol' wikipedia there's a link to a javascript implementation of UUID.

    It looks fairly elegant, and could perhaps be improved by salting with a hash of the client's IP address. This hash could perhaps be inserted into the html document server-side for use by the client-side javascript.

    UPDATE : The original site has had a shuffle, here is the updated version

    评论
    解决 无用
    打赏 举报
  • 乱世@小熊 2014-04-04 07:13

    For those wanting an rfc4122 version 4 compliant solution with speed considerations (few calls to Math.random()):

    function UUID() {
        var nbr, randStr = "";
        do {
            randStr += (nbr = Math.random()).toString(16).substr(2);
        } while (randStr.length < 30);
        return [
            randStr.substr(0, 8), "-",
            randStr.substr(8, 4), "-4",
            randStr.substr(12, 3), "-",
            ((nbr*4|0)+8).toString(16), // [89ab]
            randStr.substr(15, 3), "-",
            randStr.substr(18, 12)
            ].join("");
    }
    

    The above function should have a decent balance between speed and randomness.

    评论
    解决 无用
    打赏 举报
  • perhaps? 2014-04-04 07:13

    It's just a simple AJAX call...

    If anyone is still interested, here's my solution.

    On the server side:

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

    On the client side:

    var myNewGuid = null;
    PageMethods.GenerateGuid(
        function(result, userContext, methodName)
        {
            myNewGuid = result;
        },
        function()
        {
            alert("WebService call failed.");
        }
    );
    
    评论
    解决 无用
    打赏 举报
  • 三生石@ 2014-04-04 07:13

    From sagi shkedy's technical blog:

    function generateGuid() {
      var result, i, j;
      result = '';
      for(j=0; j<32; j++) {
        if( j == 8 || j == 12|| j == 16|| j == 20) 
          result = result + '-';
        i = Math.floor(Math.random()*16).toString(16).toUpperCase();
        result = result + i;
      }
      return result;
    }
    

    There are other methods that involve using an ActiveX control, but stay away from these!

    EDIT: I thought it was worth pointing out that no GUID generator can guarantee unique keys (check the wikipedia article). There is always a chance of collisions. A GUID simply offers a large enough universe of keys to reduce the change of collisions to almost nil.

    评论
    解决 无用
    打赏 举报
  • YaoRaoLov 2014-04-04 07:13

    This create version 4 UUID (created from pseudo random numbers) :

    function uuid()
    {
       var chars = '0123456789abcdef'.split('');
    
       var uuid = [], rnd = Math.random, r;
       uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
       uuid[14] = '4'; // version 4
    
       for (var i = 0; i < 36; i++)
       {
          if (!uuid[i])
          {
             r = 0 | rnd()*16;
    
             uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
          }
       }
    
       return uuid.join('');
    }
    

    Here is a sample of the UUIDs generated :

    682db637-0f31-4847-9cdf-25ba9613a75c
    97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
    2eed04c9-2692-456d-a0fd-51012f947136
    
    评论
    解决 无用
    打赏 举报
  • ℙℕℤℝ 2014-04-04 07:13

    JavaScript project on GitHub - https://github.com/LiosK/UUID.js

    UUID.js The RFC-compliant UUID generator for JavaScript.

    See RFC 4122 http://www.ietf.org/rfc/rfc4122.txt.

    Features Generates RFC 4122 compliant UUIDs.

    Version 4 UUIDs (UUIDs from random numbers) and version 1 UUIDs (time-based UUIDs) are available.

    UUID object allows a variety of access to the UUID including access to the UUID fields.

    Low timestamp resolution of JavaScript is compensated by random numbers.

    评论
    解决 无用
    打赏 举报
  • elliott.david 2014-04-04 07:13

    I know, it is an old question. Just for completeness, if your environment is SharePoint, there is a utility function called SP.Guid.newGuid (msdn link) which creates a new guid. This function is inside the sp.init.js file. If you rewrite this function (to remove some other dependencies from other private functions), it looks like this:

    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;
    };
    
    评论
    解决 无用
    打赏 举报
  • ℙℕℤℝ 2014-04-04 07:13

    There is a jQuery plugin that handles Guid's nicely @ http://plugins.jquery.com/project/GUID_Helper

    jQuery.Guid.Value()
    

    Returns value of internal Guid. If no guid has been specified, returns a new one (value is then stored internally).


    jQuery.Guid.New()
    

    Returns a new Guid and sets it's value internally.


    jQuery.Guid.Empty()
    

    Returns an empty Guid 00000000-0000-0000-0000-000000000000.


    jQuery.Guid.IsEmpty()
    

    Returns boolean. True if empty/undefined/blank/null.


    jQuery.Guid.IsValid()
    

    Returns boolean. True valid guid, false if not.


    jQuery.Guid.Set()
    

    Retrns Guid. Sets Guid to user specified Guid, if invalid, returns an empty guid.

    评论
    解决 无用
    打赏 举报
  • from.. 2014-04-04 07:13

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

    function generateQuickGuid() {
        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. Dashes can be trivially added if human-readability matters.

    Here are usage examples and timings for this function and several of this question's other answers. The timing was performed under Chrome m25, 10 million iterations each.

    >>> 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
    

    Here is the timing code.

    var r;
    console.time('t'); 
    for (var i = 0; i < 10000000; i++) { 
        r = FuncToTest(); 
    };
    console.timeEnd('t');
    
    评论
    解决 无用
    打赏 举报
  • ℡Wang Yan 2014-04-04 07:13

    Weird that no one has mentioned this yet but for completeness, there's a plethora of guid generators on npm I'm willing to bet most of them work in browser too.

    评论
    解决 无用
    打赏 举报
  • 旧行李 2014-04-04 07:13

    For an RFC4122 version 4 compliant solution, this one-liner(ish) solution is the most compact I could come up with.:

    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: Be aware that UUID uniqueness relies heavily on the underlying random number generator (RNG). The solution above uses Math.random() for brevity, however Math.random() is not guaranteed to be a high-quality RNG. See Adam Hyland's excellent writeup on Math.random() for details. For a more robust solution, consider something like the uuid module[Disclaimer: I'm the author], which uses higher quality RNG APIs where available.

    Update, 2015-08-26: As a side-note, this gist describes how to determine how many IDs can be generated before reaching a certain probability of collision. For example, with 3.26x1015 version 4 RFC4122 UUIDs you have a 1-in-a-million chance of collision.

    Update, 2017-06-28: A good article from Chrome developers discussing the state of Math.random PRNG quality in Chrome, Firefox, and Safari. tl;dr - As of late-2015 it's "pretty good", but not cryptographic quality. To address that issue, here's an updated version of the above solution that uses ES6, the crypto API, and a bit of JS wizardy I can't take credit for:

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

    </div>
    
    评论
    解决 无用
    打赏 举报
  • Lotus@ 2014-04-04 07:13

    broofa's answer is pretty slick, indeed - impressively clever, really... rfc4122 compliant, somewhat readable, and compact. Awesome!

    But if you're looking at that regular expression, those many replace() callbacks, toString()'s and Math.random() function calls (where he's only using 4 bits of the result and wasting the rest), you may start to wonder about performance. Indeed, joelpt even decided to toss out RFC for generic GUID speed with generateQuickGUID.

    But, can we get speed and RFC compliance? I say, YES! Can we maintain readability? Well... Not really, but it's easy if you follow along.

    But first, my results, compared to broofa, guid (the accepted answer), and the non-rfc-compliant 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.
    

    So by my 6th iteration of optimizations, I beat the most popular answer by over 12X, the accepted answer by over 9X, and the fast-non-compliant answer by 2-3X. And I'm still rfc4122 compliant.

    Interested in how? I've put the full source on http://jsfiddle.net/jcward/7hyaC/3/ and on http://jsperf.com/uuid-generator-opt/4

    For an explanation, let's start with broofa's code:

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

    So it replaces x with any random hex digit, y with random data (except forcing the top 2 bits to 10 per the RFC spec), and the regex doesn't match the - or 4 characters, so he doesn't have to deal with them. Very, very slick.

    The first thing to know is that function calls are expensive, as are regular expressions (though he only uses 1, it has 32 callbacks, one for each match, and in each of the 32 callbacks it calls Math.random() and v.toString(16)).

    The first step toward performance is to eliminate the RegEx and its callback functions and use a simple loop instead. This means we have to deal with the - and 4 characters whereas broofa did not. Also, note that we can use String Array indexing to keep his slick String template architecture:

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

    Basically, the same inner logic, except we check for - or 4, and using a while loop (instead of replace() callbacks) gets us an almost 3X improvement!

    The next step is a small one on the desktop but makes a decent difference on mobile. Let's make fewer Math.random() calls and utilize all those random bits instead of throwing 87% of them away with a random buffer that gets shifted out each iteration. Let's also move that template definition out of the loop, just in case it helps:

    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
    }
    

    This saves us 10-30% depending on platform. Not bad. But the next big step gets rid of the toString function calls altogether with an optimization classic - the look-up table. A simple 16-element lookup table will perform the job of toString(16) in much less time:

    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
    }
    

    The next optimization is another classic. Since we're only handling 4-bits of output in each loop iteration, let's cut the number of loops in half and process 8-bits each iteration. This is tricky since we still have to handle the RFC compliant bit positions, but it's not too hard. We then have to make a larger lookup table (16x16, or 256) to store 0x00 - 0xff, and we build it only once, outside the e5() function.

    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
    }
    

    I tried an e6() that processes 16-bits at a time, still using the 256-element LUT, and it showed the diminishing returns of optimization. Though it had fewer iterations, the inner logic was complicated by the increased processing, and it performed the same on desktop, and only ~10% faster on mobile.

    The final optimization technique to apply - unroll the loop. Since we're looping a fixed number of times, we can technically write this all out by hand. I tried this once with a single random variable r that I kept re-assigning, and performance tanked. But with four variables assigned random data up front, then using the lookup table, and applying the proper RFC bits, this version smokes them all:

    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 - UUID.generate()

    The funny thing is, generating 16 bytes of random data is the easy part. The whole trick is expressing it in String format with RFC compliance, and it's most tightly accomplished with 16 bytes of random data, an unrolled loop and lookup table.

    I hope my logic is correct -- it's very easy to make a mistake in this kind of tedious bit-work. But the outputs look good to me. I hope you enjoyed this mad ride through code optimization!

    Be advised: my primary goal was to show and teach potential optimization strategies. Other answers cover important topics such as collisions and truly random numbers, which are important for generating good UUIDs.

    评论
    解决 无用
    打赏 举报
  • 胖鸭 2014-04-04 07:13

    Here's some code based on RFC 4122, section 4.4 (Algorithms for Creating a UUID from Truly Random or Pseudo-Random Number).

    function createUUID() {
        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789abcdef";
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";
    
        var uuid = s.join("");
        return uuid;
    }
    
    评论
    解决 无用
    打赏 举报
  • from.. 2014-04-04 07:13

    I really like how clean Broofa's answer is, but it's unfortunate that poor implementations of Math.random leave the chance for collision.

    Here's a similar RFC4122 version 4 compliant solution that solves that issue by offsetting the first 13 hex numbers by a hex portion of the timestamp. That way, even if Math.random is on the same seed, both clients would have to generate the UUID at the exact same millisecond (or 10,000+ years later) to get the same UUID:

    function generateUUID() { // Public Domain/MIT
        var d = new Date().getTime();
        if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
            d += performance.now(); //use high-precision timer if available
        }
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
    }
    


    Here's a fiddle to test.

    评论
    解决 无用
    打赏 举报
  • 7*4 2014-07-22 15:31

    Well, this has a bunch of answers already, but unfortunately there's not a "true" random in the bunch. The version below is an adaptation of broofa's answer, but updated to include a "true" random function that uses crypto libraries where available, and the Alea() function as a fallback.

      Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
      Math.trueRandom = (function() {
      var crypt = window.crypto || window.msCrypto;
    
      if (crypt && crypt.getRandomValues) {
          // if we have a crypto library, use it
          var random = function(min, max) {
              var rval = 0;
              var range = max - min;
              if (range < 2) {
                  return min;
              }
    
              var bits_needed = Math.ceil(Math.log2(range));
              if (bits_needed > 53) {
                throw new Exception("We cannot generate numbers larger than 53 bits.");
              }
              var bytes_needed = Math.ceil(bits_needed / 8);
              var mask = Math.pow(2, bits_needed) - 1;
              // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111
    
              // Create byte array and fill with N random numbers
              var byteArray = new Uint8Array(bytes_needed);
              crypt.getRandomValues(byteArray);
    
              var p = (bytes_needed - 1) * 8;
              for(var i = 0; i < bytes_needed; i++ ) {
                  rval += byteArray[i] * Math.pow(2, p);
                  p -= 8;
              }
    
              // Use & to apply the mask and reduce the number of recursive lookups
              rval = rval & mask;
    
              if (rval >= range) {
                  // Integer out of acceptable range
                  return random(min, max);
              }
              // Return an integer that falls within the range
              return min + rval;
          }
          return function() {
              var r = random(0, 1000000000) / 1000000000;
              return r;
          };
      } else {
          // From http://baagoe.com/en/RandomMusings/javascript/
          // Johannes Baagøe <baagoe@baagoe.com>, 2010
          function Mash() {
              var n = 0xefc8249d;
    
              var mash = function(data) {
                  data = data.toString();
                  for (var i = 0; i < data.length; i++) {
                      n += data.charCodeAt(i);
                      var h = 0.02519603282416938 * n;
                      n = h >>> 0;
                      h -= n;
                      h *= n;
                      n = h >>> 0;
                      h -= n;
                      n += h * 0x100000000; // 2^32
                  }
                  return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
              };
    
              mash.version = 'Mash 0.9';
              return mash;
          }
    
          // From http://baagoe.com/en/RandomMusings/javascript/
          function Alea() {
              return (function(args) {
                  // Johannes Baagøe <baagoe@baagoe.com>, 2010
                  var s0 = 0;
                  var s1 = 0;
                  var s2 = 0;
                  var c = 1;
    
                  if (args.length == 0) {
                      args = [+new Date()];
                  }
                  var mash = Mash();
                  s0 = mash(' ');
                  s1 = mash(' ');
                  s2 = mash(' ');
    
                  for (var i = 0; i < args.length; i++) {
                      s0 -= mash(args[i]);
                      if (s0 < 0) {
                          s0 += 1;
                      }
                      s1 -= mash(args[i]);
                      if (s1 < 0) {
                          s1 += 1;
                      }
                      s2 -= mash(args[i]);
                      if (s2 < 0) {
                          s2 += 1;
                      }
                  }
                  mash = null;
    
                  var random = function() {
                      var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                      s0 = s1;
                      s1 = s2;
                      return s2 = t - (c = t | 0);
                  };
                  random.uint32 = function() {
                      return random() * 0x100000000; // 2^32
                  };
                  random.fract53 = function() {
                      return random() +
                          (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
                  };
                  random.version = 'Alea 0.9';
                  random.args = args;
                  return random;
    
              }(Array.prototype.slice.call(arguments)));
          };
          return Alea();
      }
    }());
    
    Math.guid = function() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)    {
          var r = Math.trueRandom() * 16 | 0,
              v = c == 'x' ? r : (r & 0x3 | 0x8);
          return v.toString(16);
      });
    };
    
    评论
    解决 无用
    打赏 举报
  • local-host 2015-03-08 00:39

    I wanted to understand broofa's answer, so I expanded it and added comments:

    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);
            }
        );
    };
    
    评论
    解决 无用
    打赏 举报
  • derek5. 2015-10-13 01:50

    You can use node-uuid (https://github.com/kelektiv/node-uuid)

    Simple, fast generation of RFC4122 UUIDS.

    Features:

    • Generate RFC4122 version 1 or version 4 UUIDs
    • Runs in node.js and browsers.
    • Cryptographically strong random # generation on supporting platforms.
    • Small footprint (Want something smaller? Check this out!)

    Install Using NPM:

    npm install uuid
    

    Or Using uuid via browser:

    Download Raw File (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Download Raw File (uuid v4): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js


    Want even smaller? Check this out: https://gist.github.com/jed/982883


    Usage:

    // Generate a v1 UUID (time-based)
    const uuidV1 = require('uuid/v1');
    uuidV1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
    
    // Generate a v4 UUID (random)
    const uuidV4 = require('uuid/v4');
    uuidV4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
    
    // Generate a v5 UUID (namespace)
    const uuidV5 = require('uuid/v5');
    
    // ... using predefined DNS namespace (for domain names)
    uuidV5('hello.example.com', v5.DNS)); // -> 'fdda765f-fc57-5604-a269-52a7df8164ec'
    
    // ... using predefined URL namespace (for, well, URLs)
    uuidV5('http://example.com/hello', v5.URL); // -> '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'
    
    // ... using a custom namespace
    const MY_NAMESPACE = '(previously generated unique uuid string)';
    uuidV5('hello', MY_NAMESPACE); // -> '90123e1c-7512-523e-bb28-76fab9f2f73d'
    

    ES6:

    import uuid from 'uuid/v4';
    const id = uuid();
    
    评论
    解决 无用
    打赏 举报
  • ~Onlooker 2017-05-19 20:50
    var uniqueId = Math.random().toString(36).substring(2) 
                   + (new Date()).getTime().toString(36);
    

    If ID's are generated more than 1 millisecond apart, they are 100% unique.

    If two ID's are generated at shorter intervals, and assuming that the random method is truly random, this would generate ID's that are 99.99999999999999% likely to be globally unique (collision in 1 of 10^15)

    You can increase this number by adding more digits, but to generate 100% unique ID's you will need to use a global counter.

    document.getElementById("unique").innerHTML =
      Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
    <div id="unique">
    </div>

    </div>
    
    评论
    解决 无用
    打赏 举报
  • MAO-EYE 2017-07-09 13:01

    ES6 sample

    const guid=()=> {
      const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
      return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
    }
    
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题