Как создать uuid для углового, который соответствует RFC 4122 [дубликат]

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

3355
задан 7 revs, 5 users 50% 27 December 2014 в 00:36
поделиться

30 ответов

Было несколько попыток. Возникает вопрос: хотите ли вы иметь фактические GUID или просто случайные числа, которые выглядят как GUID?

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

Однако обратите внимание, что такие значения не являются подлинными GUID.

Невозможно генерировать реальные GUID в Javascript, потому что они зависят от свойства локального компьютера, которые браузеры не раскрывают. Вам нужно будет использовать службы, специфичные для ОС, такие как ActiveX: http://p2p.wrox.com/topicindex/20339.htm

Изменить: неверно - RFC4122 позволяет случайным образом («версия 4»). См. Другие ответы для специфики.

Примечание: предоставленный фрагмент кода не соответствует RFC4122, который требует, чтобы версия (4) была интегрирована в сгенерированную выходную строку. Не используйте этот ответ, если вам нужны соответствующие GUID.

Использование:

var uuid = guid();

Демонстрация:

function guid() {
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
    s4() + '-' + s4() + s4() + 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"/>

1914
ответ дан 17 revs, 12 users 24% 19 August 2018 в 08:22
поделиться
  • 1
    На самом деле RFC допускает UUID, которые создаются из случайных чисел. Вам просто нужно обмануть пару бит, чтобы идентифицировать их как таковые. См. Раздел 4.4. Алгоритмы создания UUID из действительно случайных или псевдослучайных чисел: rfc-archive.org/getrfc.php?rfc=4122 – Jason DeFontes 19 September 2008 в 21:28
  • 2
    Может ли кто-нибудь объяснить этот код мне? Похоже, что функция S4 пытается получить случайное шестнадцатеричное число между 0x10000 и 0x20000, а затем выводит последние 4 цифры. Но почему побитовое или с 0? Разве это не должно быть парнем? Кроме того, является 0x10000 до 0x20000 просто взломать, чтобы избежать иметь дело с ведущими 0? – Cory 26 October 2010 в 23:56
  • 3
    В Chrome этот код не всегда генерирует правильный GUID размера. Длина колеблется между 35 и 36 – cdeutsch 13 September 2012 в 22:38
  • 4
    Как может так явно ошибочный ответ получить так много upvotes? Даже код неправильный, так как в правой позиции нет 4. en.wikipedia.org/wiki/Globally_unique_identifier – Dennis Krøger 21 January 2013 в 11:28
  • 5
    Этот ответ был нарушен в редакции 5, когда «1 + ....» и "подстрока (1)" были удалены. Эти биты гарантировали согласованную длину. – Segfault 7 February 2013 в 21:12
Ответ

broofa довольно гладкий, действительно - впечатляюще умный, действительно ... rfc4122 совместимый, несколько читаемый и компактный. Awesome!

Но если вы смотрите на это регулярное выражение, эти многие replace() обратные вызовы, toString() и Math.random() вызовы функций (где он использует только 4 бита результата и тратит впустую остальное), вы можете начать задаваться вопросом о производительности. Действительно, joelpt даже решил выбросить RFC для общей скорости GUID с помощью generateQuickGUID.

Но можем ли мы получить соответствие скорости и RFC? Я сказал да! Можем ли мы поддерживать читаемость? Ну ... Не совсем, но это легко, если вы будете следовать.

Но сначала мои результаты, по сравнению с broofa, 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-й итерации оптимизаций я обыграл самый популярный ответ более чем на 12X, принятый ответ более чем на 9X и быстрый ответ, не отвечающий требованиям 2-3X. И я все еще совместим с rfc4122.

Заинтересованы в том, как? Я поставил полный источник на http://jsfiddle.net/jcward/7hyaC/3/ и на http://jsperf.com/uuid-generator-opt/4

Для объяснения, давайте начнем с кода брофы:

'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 любой случайной шестнадцатеричной цифрой, y со случайными данными (кроме заставляя верхние 2 бита 10 в спецификации RFC), и регулярное выражение не соответствует символам - или 4, поэтому ему не нужно иметь дело с ними.

Первое, что нужно знать, это то, что вызовы функций дороги, как и регулярные выражения (хотя он использует только 1, имеет 32 обратных вызова, по одному для каждого совпадения и в каждом из

Первый шаг к производительности - это исключить RegEx и его функции обратного вызова и вместо этого использовать простой цикл. Это означает, что мы должны иметь дело с символами - и 4, тогда как broofa этого не делал. Также обратите внимание, что мы можем использовать индексирование 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()) дает нам почти 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, но это не так сложно. Затем мы должны сделать более крупную таблицу поиска (16x16 или 256) для хранения 0x00 - 0xff, и мы построим ее только один раз, вне функции e5 ().

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
}

Я попробовал e6 ( ), который обрабатывает 16 бит за раз, все еще используя 256-элементный LUT, и показал уменьшающуюся отдачу от оптимизации. Хотя у него было меньше итераций, внутренняя логика осложнялась увеличением обработки, и она выполнялась на рабочем столе одинаково, и только на 10% быстрее на мобильном устройстве.

Последний способ оптимизации - развернуть цикл , Поскольку мы зацикливаемся фиксированным числом раз, мы можем технически написать все это вручную. Я попробовал это один раз с помощью одной случайной переменной r, которую я продолжал переустанавливать, и производительность танков. Но с четырьмя переменными присваиваются случайные данные спереди, затем, используя таблицу поиска и применяя правильные биты 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];
}

Модуализировано: http: // jcward. com / UUID.js - UUID.generate()

Самое забавное: генерировать 16 байт случайных данных - это легкая часть. Весь трюк выражает его в формате String с соблюдением RFC, и он наиболее сильно выполняется с 16 байтами случайных данных, развернутым циклом и поисковой таблицей.

Надеюсь, моя логика правильная - это очень просто чтобы совершить ошибку в такой утомительной бит-работе. Но результаты выглядят хорошо для меня. Надеюсь, вам понравилась эта безумная поездка с помощью оптимизации кода!

. Будьте внимательны: моя основная цель состояла в том, чтобы показать и научить потенциальным стратегиям оптимизации. Другие ответы охватывают важные темы, такие как столкновения и действительно случайные числа, которые важны для создания хороших UUID.

309
ответ дан 11 revs, 2 users 96% 19 August 2018 в 08:22
поделиться
  • 1
    jsperf.com позволит вам записывать данные и просматривать результаты в браузерах и устройствах. – fearphage 24 February 2014 в 17:40
  • 2
    Привет @chad, хорошие вопросы. k может быть перемещен за пределы, но это не улучшило производительность выше и делает мессенджер более бесполезным. И построение массива и соединение по возвращению странно убивают производительность. Но опять же, не стесняйтесь экспериментировать! – Jeff Ward 24 February 2014 в 21:23
  • 3
    Мне было бы интересно посмотреть, как сравнивается node-uuid.js. В моей работе я начал с большей сосредоточенности на производительности, некоторые из которых остались. Но с тех пор я отказался от этого, предпочитая иметь более читаемый / поддерживаемый код. Причина в том, что uuid perf просто не проблема в реальном мире. Uuids обычно создаются в сочетании с гораздо более медленными операциями (например, созданием сетевого запроса, созданием и сохранением объекта модели), где бритье нескольких микросекунд от вещей просто не имеет значения. – broofa 2 June 2015 в 15:14
  • 4
    Этот код по-прежнему содержит пару ошибок: строки Math.random()*0xFFFFFFFF должны быть Math.random()*0x100000000 для полной случайности, а вместо |0 следует использовать >>>0, чтобы сохранить значения без знака (хотя с текущим кодом, я думаю, он получает далеко, даже если они подписаны). Наконец, в наши дни было бы очень неплохо использовать window.crypto.getRandomValues, если это возможно, и вернуться к Math.random, только если это абсолютно необходимо. Math.random может иметь менее 128 бит энтропии, и в этом случае это будет более уязвимым для коллизий, чем это необходимо. – Dave 18 July 2015 в 17:55
  • 5
    Применили все советы @Dave и опубликовали очень аккуратный источник ES6 / Babel здесь: codepen.io/avesus/pen/wgQmaV?editors=0012 – Brian Haak 10 February 2017 в 21:51

Самый быстрый GUID, как метод генератора строк в формате XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Это не создает стандартно-совместимый GUID.

Десять миллионов исполнений этой реализации занимают всего 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() возвращает десятичную число между 0 и 1 с 16 цифрами после точки десятичной дроби (например, 0.4363923368509859).
  • Затем мы берем это число и преобразуем его в строку с базой 16 (из приведенного выше примера мы будем get 0.6fb7687f). Math.random().toString(16).
  • Затем мы отключим префикс 0. (0.6fb7687f => 6fb7687f) и получим строку с восемью шестнадцатеричными символами. (Math.random().toString(16).substr(2,8).
  • Иногда функция Math.random() возвращает более короткое число (например, 0.4363), из-за нулей в конце (из приведенного выше примера фактически число 0.4363000000000000). Вот почему я добавляю к этой строке "000000000" (строка с девятью нулями), а затем отрезаю ее функцией substr(), чтобы сделать ее девятью символами (заполнение нулей вправо).
  • Причина добавления ровно девяти нулей из-за худшего сценария, когда функция Math.random() вернет ровно 0 или 1 (вероятность 1/10 ^ 16 для каждого из них). Вот почему нам нужно было добавить к нему девять нулей ("0"+"000000000" или "1"+"000000000"), а затем отрезать его от второго индекса (3-й символ) длиной до восьми символов. Для остальных случаев добавление нулей не повредит результату, потому что оно все равно отключает его. Math.random().toString(16)+"000000000").substr(2,8).

Сборка:

  • GUID находится в следующем формате XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • Я разделил GUID на 4 части, каждая часть разделена на 2 типа (или форматы): XXXXXXXX и -XXXX-XXXX.
  • Теперь я создаю GUID, используя эти 2 типа, чтобы собрать GUID с вызовом 4 штуки, следующим образом: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Чтобы различаться между этими двумя типами, я добавил параметр флага функции создания пары _p8(s), параметр s сообщает функция, добавить ли тире или нет.
  • В конце концов мы создаем GUID со следующей цепочкой: _p8() + _p8(true) + _p8(true) + _p8() и возвращаем его.

Ссылка на этот пост в моем блоге

Наслаждайтесь! : -)

79
ответ дан 12 revs, 3 users 95% 19 August 2018 в 08:22
поделиться
  • 1
    Эта реализация неверна. Определенные символы GUID требуют специального лечения (например, 13-я цифра должна быть номером 4). – JLRishe 12 November 2013 в 10:12
  • 2
    @JLRishe, вы правы, это не соответствует стандартам RFC4122. Но это все еще случайная строка, которая выглядит как GUID. Приветствия :-) – Slavik Meltser 25 November 2013 в 00:33
  • 3
    Хорошая работа, но классические методы оптимизации делают ее быстрее на 6X (в моем браузере) - см. мой ответ – Jeff Ward 25 February 2014 в 21:23

Для решения, совместимого с RFC4122 версии 4, это однострочное (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(), однако Math.random() является , а не гарантированным высококачественным RNG. Для получения дополнительной информации см. Превосходную запись Адама Хиланда на Math.random () . Для более надежного решения рассмотрим что-то вроде модуля uuid [Отказ от ответственности: я автор], который использует доступные API RNG более высокого качества, где они доступны.

Update, 2015-08 -26: Как примечание, этот gist описывает, как определить, сколько идентификаторов может быть сгенерировано до достижения определенной вероятности столкновения. Например, при использовании UUID с 3.26x1015 версии 4 RFC4122 у вас есть вероятность столкновения 1-в-миллион.

Обновление, 2017-06-28: хорошая статья от разработчиков Chrome обсуждает состояние Math.random качества PRNG в Chrome, Firefox и Safari. tl; dr - По состоянию на конец 2015 года это «неплохо», но не криптографическое. Чтобы решить эту проблему, приведена обновленная версия вышеупомянутого решения, которое использует ES6, API crypto и немного JS wizardy. Я не могу взять кредит за :

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

3160
ответ дан 12 revs, 5 users 65% 19 August 2018 в 08:22
поделиться
  • 1
    Можно ли использовать этот код для создания уникальных идентификаторов на клиенте, а затем использовать эти идентификаторы в качестве первичных ключей для сохранения объектов на сервере? – Muxa 21 April 2011 в 08:04
  • 2
    ... (продолжение) Шансы двух идентификаторов, генерируемых этой функцией, сталкиваются, буквально, астрономически малыми. Все, кроме 6 из 128 бит идентификатора, генерируются случайным образом, что означает, что для любых двух идентификаторов существует вероятность 1 из 2 ^^ 122 (или 5.3x10 ^^ 36), с которой они столкнутся. – broofa 28 April 2011 в 23:37
  • 3
    Я поставил вопрос о столкновениях stackoverflow.com/questions/6906916/… – Muxa 2 August 2011 в 04:23
  • 4
    Несомненно, ответ на вопрос @ Мукса «нет»? Никогда нельзя доверять чему-то, что пришло от клиента. Я думаю, это зависит от того, насколько вероятны ваши пользователи, чтобы открыть консоль javascript и вручную изменить переменную так, чтобы они захотели. Или они могли бы просто ПОСЛАТЬ вам обратно идентификатор, который они хотят. Это также зависит от того, будет ли пользователь выбирать свой собственный идентификатор, чтобы вызвать уязвимости. В любом случае, если это идентификатор случайных чисел, который входит в таблицу, я, вероятно, буду генерировать его на стороне сервера, чтобы я знал, что у меня есть контроль над процессом. – Cam Jackson 1 November 2012 в 16:34
  • 5
    @DrewNoakes - UUID - это не просто строка абсолютно случайных #. "4" является версией uuid (4 = «случайный»). & Quot; y & quot; метки, в которых должен быть встроен вариант uuid (полевая компоновка, в основном). Подробнее см. В разделах 4.1.1 и 4.1.3 из ietf.org/rfc/rfc4122.txt . – broofa 28 November 2012 в 00:13

Мне очень нравится, насколько чистый ответ Бровафа , но, к сожалению, плохие реализации Math.random оставляют шанс для столкновения.

Вот аналогичное решение, совместимое с RFC4122 версии 4, которое решает эту проблему, компенсируя первые 13 шестнадцатеричных чисел шестнадцатеричной частью метки времени. Таким образом, даже если Math.random находится на одном семестре, оба клиента должны будут генерировать UUID в то же самое миллисекунду (или через 10 000 лет позже), чтобы получить тот же 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);
    });
}

Вот скрипка для тестирования.

672
ответ дан 14 revs, 7 users 80% 19 August 2018 в 08:22
поделиться
  • 1
    Помните, что new Date().getTime() не обновляется каждые миллисекунды. Я не уверен, как это влияет на ожидаемую случайность вашего алгоритма. – devios1 18 March 2012 в 19:27
  • 2
    Я думаю, что это лучшие ответы просто потому, что он использует дату в генерации. Однако, если у вас есть современный стек браузера, я рекомендую Date.now() - new Date().getTime() – Fresheyeball 28 June 2013 в 20:47
  • 3
    performance.now будет еще лучше. В отличие от Date.now, метки времени, возвращаемые performance.now(), не ограничены разрешением в один миллисекунду. Вместо этого они представляют собой числа с плавающей запятой с точностью до микросекундной точности . Кроме того, в отличие от Date.now, значения, возвращаемые функцией performance.now () , всегда увеличиваются с постоянной скоростью , независимо от системных часов, которые могут быть скорректированы вручную или искажены программным обеспечением, таким как Network Time Protocol. – daniellmb 13 March 2014 в 06:25
  • 4
    @daniellmb Вероятно, вы должны были привязаться к MDN или другому, чтобы показать реальную документацию, а не polyfill;) – Martin 8 July 2014 в 20:38
  • 5
    FYI, за нижний колонтитул сайта, все пользовательские взносы на сайте доступны под лицензией cc by-sa 3.0. – Xiong Chiamiov 4 February 2015 в 02:34

Вот комбинация голосового ответа с обходным путем для столкновений Chrome :

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

В jsbin , если вы хотите проверить его.

57
ответ дан 3 revs 19 August 2018 в 08:22
поделиться
  • 1
    Я считаю, что в IE это фактически window.msCrypto вместо window.crypto. Может быть, приятно проверить их оба. См. msdn.microsoft.com/en-us/library/ie/dn265046 (v = vs.85) .aspx – herbrandson 17 April 2014 в 21:44
  • 2
    обратите внимание, что первая версия, одна `window.crypto.getRandomValues ​​, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`, дает xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. – humanityANDpeace 3 September 2016 в 07:58

В техническом блоге sagi shkedy :

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

Существуют и другие методы, которые включают использование элемента управления ActiveX, но держитесь подальше от них!

EDIT: Я думал, что стоит отметить, что никакой GUID-генератор не может гарантировать уникальные ключи (проверьте статью wikipedia ). Всегда есть вероятность столкновения. GUID просто предлагает достаточно большой набор ключей, чтобы уменьшить смену столкновений почти до нуля.

30
ответ дан 3 revs, 2 users 93% 19 August 2018 в 08:22
поделиться
  • 1
    Обратите внимание, что это не GUID в техническом смысле, потому что он не делает ничего, чтобы гарантировать уникальность. Это может быть или не иметь значения в зависимости от вашего приложения. – Stephen Deken 19 September 2008 в 21:07
  • 2
    То же самое касается ответа Стивена. Если вам нужна уникальность, определите ее на стороне сервера, где, надеюсь, вы сможете подойти к правильному алгоритму! – Ray Hayes 19 September 2008 в 21:08
  • 3
    Никакой GUID не гарантированно уникален ... Вселенная созданных ключей просто достаточно велика, чтобы сделать столкновения практически невозможными. – Prestaul 19 September 2008 в 21:13
  • 4
    Быстрая заметка о производительности. Это решение создает 36 строк для получения единственного результата. Если производительность критическая, подумайте о создании массива и присоединении в соответствии с рекомендациями: tinyurl.com/y37xtx Дальнейшие исследования показывают, что это может не иметь значения, поэтому YMMV: tinyurl.com/3l7945 – Brandon DuRette 22 September 2008 в 19:14
  • 5
    Что касается уникальности, то стоит отметить, что версии 1,3 и 5 UUID детерминированы, как вариант 4. Если входы в эти генераторы uuid - идентификатор узла в v1, пространство имен и имя в v3 и v5 - уникальны (как и предполагалось), то получившиеся UUID будут уникальными. Теоретически, во всяком случае. – broofa 29 June 2017 в 13:26

Я хотел понять ответ broofa, поэтому я расширил его и добавил комментарии:

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);
        }
    );
};
69
ответ дан 4 revs 19 August 2018 в 08:22
поделиться
  • 1
    Исходный файл мертв. – Edward Olamisan 13 April 2017 в 03:50
  • 2
    @Edward Olamisan Обновлен новый источник для замены устаревшей версии. – Kyros Koh 14 April 2017 в 21:31
  • 3
    Это правильный ответ, тбх. Просто используйте эту библиотеку. – justin.m.chase 20 May 2017 в 05:29
  • 4
    Версия ES6: import uuid from 'uuid/v4'; let id = uuid(); – justin.m.chase 20 May 2017 в 05:30
  • 5
    Это не UUID? – Marco Kerwitz 27 December 2017 в 00:28
  • 6
    Нет. UUID / GUID - это 122-разрядный (+ 6 зарезервированных бит) номер. это может гарантировать уникальность через глобальную службу встречных операций, но часто она реле вовремя, MAC-адрес и случайность. UUID не случайны! UID, который я предлагаю здесь, не полностью сжат. Вы можете сжать его до 122-битного целого числа, добавить 6 предопределенных бит и дополнительных случайных битов (удалить несколько бит таймера), и вы получите совершенно сформированный UUID / GUID, который вам тогда придется преобразовать в hex. Для меня это не добавляет ничего, кроме соответствия длине идентификатора. – Simon Rigét 18 February 2018 в 01:05
  • 7
    Релевание по MAC-адресам для уникальности на виртуальных машинах - плохая идея! – Simon Rigét 18 February 2018 в 01:48
  • 8
    @ justin.m.chase не должно быть const id = uuid – Kermit_ice_tea 22 February 2018 в 02:07

Простой модуль 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());

Использование:

< blockquote>

Guid.newGuid ()

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

Guid.empty

"00000000-0000- 0000-0000-000000000000 "

28
ответ дан 4 revs, 3 users 72% 19 August 2018 в 08:22
поделиться
  • 1
    Что беспокоит ответы all , так это то, что JavaScript для JavaScript GUID как string выглядит как ok . Ваш ответ хотя бы решает более эффективное хранилище much , используя Uint16Array. Функция toString должна использовать двоичное представление в JavaScript object – Sebastian 4 May 2014 в 12:03
  • 2
    Не следует ли _cryptoGuid включить «4» в начале третьего раздела, например _guid? – row1 1 February 2015 в 22:05
  • 3
    Хороший ответ! Я преобразовал код в фрагмент и исправил проблему совместимости с IE11, согласно этому вопросу. – Matt 18 May 2017 в 11:56
  • 4
    Эти UUID, созданные этим кодом, являются либо слабыми, но RFC-совместимыми (_guid), либо сильными, но не RFC-совместимыми (_cryptoGuid). Первый использует Math.random (), который, как известно, является бедным RNG. Последний не может установить версии и варианты полей. – broofa 29 June 2017 в 13:37
  • 5
    @broofa - Что вы предложите сделать сильным и RFC-совместимым? И почему _cryptoGuid не соответствует RFC? – Matt 15 March 2018 в 10:57

Ну, у этого уже есть куча ответов, но, к сожалению, в связке нет «истинного» случайного. Нижеприведенная версия является адаптацией ответа broofa, но обновляется, чтобы включить «истинную» случайную функцию, которая использует доступные криптографические библиотеки, и функцию Alea () в качестве резервной копии.

  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);
  });
};
23
ответ дан 5 revs, 2 users 80% 19 August 2018 в 08:22
поделиться
  • 1
    Вам нужно прокомментировать строку rval = rval & mask, поскольку она усекает результат до 32 бит. Бит ops составляет всего 32 бита в JS. Более того, если вы применяете его только в конце, то три младших бита уже теряются при генерации 53-битного значения, так как первый цикл создает 56-битное значение (255 * 2 ^ 48). Вместо этого вам нужно использовать этот код: `var byte = byteArray [i]; если (p + 8 & gt; бит_определенный) байт & amp; = (255 & gt; p + 8 - bits_needed); rval + = byte * Math.pow (2, p); `Здесь вы можете увидеть тест: jsfiddle.net/xto6969y/1 – Roland Pihlakas 2 May 2015 в 08:57
  • 2
    Также вы можете использовать var crypto = window.crypto || window.msCrypto см. msdn.microsoft.com/library/dn265046 (v = vs.85) .aspx – Roland Pihlakas 2 May 2015 в 09:00
  • 3
    Обновлено по обоим пунктам. – jvenema 2 June 2015 в 14:10
  • 4
    Я использую ваш скрипт и получил «Uncaught RangeError: максимальный размер стека вызовов (...) & quot; on var byteArray = новый Uint8Array (bytes_needed); Что может быть проблемой? – AlexBerd 6 April 2016 в 08:35
  • 5
    Плохие изменения в прошлом, должно быть хорошо. – jvenema 11 April 2016 в 13:51
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:

Пересмотрен мой проект, который использовал эту функцию и не любил многословие. - Но нужна правильная случайность.

Версия, основанная на ответе Briguy37 и некоторых побитовых операторах, чтобы извлекать окна размером с размеру из буфера.

Следует придерживаться схемы RFC Type 4 (random) , так как у меня были проблемы с последним анализом неудовлетворительных uuids с UUID Java.

28
ответ дан 5 revs, 2 users 98% 19 August 2018 в 08:22
поделиться
  • 1
    На jsbin: jsbin.com/uqives/2 Стоит более подробно заявить, что это не работает на IE. Не работал и для Firefox, и в моем тесте. – ripper234 12 December 2011 в 12:04
  • 2
    Спасибо, что попробовали. Я взломал его для расширения хром. Я не проверял факты, которые я читал в Internt (tm) об поддержке Firefox. Также стоит отметить, что это не соответствует RFC, случайный (версия 4) UUID должен иметь два места с фиксированными значениями: en.wikipedia.org/wiki/… – sleeplessnerd 12 December 2011 в 19:03

Вот решение от 9 октября 2011 г. из комментария пользователя jed в 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)}

Выполняет ту же цель, что и , самый высокий рейтинг ответа , но в 50 + меньше байтов, используя принуждение, рекурсию и экспоненциальную нотацию. Для любопытных, как это работает, вот аннотированная форма более старой версии функции:

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
      )
}
52
ответ дан 9 revs, 5 users 63% 19 August 2018 в 08:22
поделиться
  • 1
    В TypeScript используйте это: export const UUID = function b (a: number): string { return a ? (a^Math.random()*16>>a/4).toString(16) : (''+[1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, b) }; – RyanNerd 7 August 2018 в 22:45

Это просто простой вызов 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.");
    }
);
10
ответ дан alekop 19 August 2018 в 08:22
поделиться
  • 1
    Ваш метод является единственным правильным способом, но проблема заключается в том, что он асинхронный, поэтому вы не можете его использовать. Кроме того, попробуйте сделать это несколько раз в 100-1000 раз, и вы будете разбивать IE (не Chrome и Firefox, хотя). Синхронные вызовы нам нужны: используйте JQuery, а не MS-PageMethod JavaScript! – Stefan Steiger 30 March 2010 в 12:46
  • 2
    Вы правы, называемые асинхронно, это не очень полезно. По иронии судьбы, в моем исходном коде используется jQuery для синхронного вызова этого метода. Вот пример: $ .ajax ({async: false, type: 'POST', url: 'MyPage.aspx / GenerateGuid', contentType: 'application / json; charset = utf-8', data: '{}', success: function (data) {// данные содержат ваш новый GUID}, fail: function (msg) {alert (msg);}}); – alekop 6 April 2010 в 00:26
  • 3
    Зачем вам нужен вызов AJAX, если вы используете ASP.NET? Просто сделайте & lt;% = Guid.NewGuid (). ToString ()% & gt; в aspx. – kape123 26 January 2012 в 03:02
  • 4
    @ kape123: Это нормально, если вам нужен только один GUID. Веб-служба позволяет создавать несколько идентификаторов GUID без перезагрузки страницы. – alekop 23 July 2013 в 02:20

Я знаю, это старый вопрос. Для полноты, если ваша среда - SharePoint, есть функция утилиты, называемая SP.Guid.newGuid ( msdn link ), которая создает новый guid. Эта функция находится внутри файла 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;
};
10
ответ дан Anatoly Mironov 19 August 2018 в 08:22
поделиться

Лучший способ:

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}
11
ответ дан Andrea Turri 19 August 2018 в 08:22
поделиться

образец ES6

const guid=()=> {
  const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
  return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}
10
ответ дан Behnam Mohammadi 19 August 2018 в 08:22
поделиться

Из good ol 'wikipedia есть ссылка на javascript-реализацию UUID.

Он выглядит довольно элегантно и, возможно, может быть улучшен путем соления с хэшем Айпи адрес. Этот хэш, возможно, может быть вставлен в сервер html-документа для использования на стороне клиента javascript.

UPDATE: Исходный сайт имел перетасовку, вот обновленная версия

22
ответ дан Dan 19 August 2018 в 08:22
поделиться
  • 1
    Ссылка мертва. Можете ли вы предоставить альтернативу? – Will 12 January 2011 в 15:04
  • 2
    Эта реализация хороша, потому что в отличие от вышеперечисленных ответов также включает временную метку, которая должна улучшить уникальность в браузерах с помощью генератора случайных чисел. – Dobes Vandermeer 30 September 2011 в 01:17

Странно, что никто не упомянул об этом пока, но для полноты, существует множество генераторов guid на npm . Я готов поспорить, что большинство из них также работают в браузере.

7
ответ дан George Mauer 19 August 2018 в 08:22
поделиться
  // 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('-');
15
ответ дан jablko 19 August 2018 в 08:22
поделиться
  • 1
    Мне нравится этот подход, но будьте осторожны, что он не работает должным образом в Chrome. ". (2, 14)" часть возвращает только 8 символов, а не 12. – jalbert 14 September 2011 в 21:37

Вот полностью несовместимая, но очень эффективная реализация для генерации уникального идентификатора GUID, подобного ASCII.

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

Генерирует 26 [a-z0-9] символов, что дает UID что является более коротким и уникальным, чем GUID, совместимый с RFC. Тишины могут быть добавлены тривиально, если важна удобочитаемость человека.

Вот примеры использования и тайминги для этой функции и некоторые другие ответы на этот вопрос. Сроки выполнялись в рамках Chrome m25, по 10 миллионов итераций каждый.

>>> 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');
52
ответ дан joelpt 19 August 2018 в 08:22
поделиться

Для тех, кто хочет иметь совместимое с rfc4122 решение 4 с учетом скорости (несколько вызовов в 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("");
}

Вышеуказанная функция должна иметь приличный баланс между скоростью и случайностью.

11
ответ дан John Fowler 19 August 2018 в 08:22
поделиться

Вот код, основанный на RFC 4122 , раздел 4.4 (Алгоритмы для создания UUID из действительно случайного или псевдослучайного числа).

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;
}
138
ответ дан Kevin Hakanson 19 August 2018 в 08:22
поделиться
  • 1
    Это не создает тире, необходимые для c #, чтобы проанализировать его в System.Guid. Он выглядит следующим образом: B42A153F1D9A4F92990392C11DD684D2, когда он должен выглядеть так: B42A153F-1D9A-4F92-9903-92C11DD684D2 – Levitikon 25 October 2011 в 17:24
  • 2
    ABNF из спецификации включает в себя & quot; - & quot; символов, поэтому я обновился, чтобы быть совместимым. – Kevin Hakanson 25 October 2011 в 23:40
  • 3
    Я лично ненавижу тире, но каждому свой. Эй, вот почему мы программисты! – devios1 23 January 2012 в 18:20
  • 4
    Вы должны заранее объявить размер массива, а не определять его динамически при создании GUID. var s = new Array(36); – MgSam 25 March 2013 в 22:03
  • 5
    @Levitikon .NET Guid.Parse() должен разбирать B42A153F1D9A4F92990392C11DD684D2 в Guid просто отлично. Ему не нужно иметь дефисы. – JLRishe 12 November 2013 в 10:08

Существует плагин jQuery, который отлично обрабатывает Guid [@ g0] http://plugins.jquery.com/project/GUID_Helper

jQuery.Guid.Value()

Возвращает значение внутреннего Guid. Если не указано ни одного указателя, возвращается новый (значение затем сохраняется внутри).


jQuery.Guid.New()

Возвращает новое руководство и устанавливает его внутреннее значение.


jQuery.Guid.Empty()

Возвращает пустой Guid 00000000-0000-0000-0000-000000000000.


jQuery.Guid.IsEmpty()

Возвращает логическое значение. Истина, если пустой / undefined / blank / null.


jQuery.Guid.IsValid()

Возвращает значение boolean. True valid guid, false, если нет.


jQuery.Guid.Set()

Retrns Guid. Устанавливает Guid для указанного пользователем Guid, если недействительно, возвращает пустое руководство.

10
ответ дан Levitikon 19 August 2018 в 08:22
поделиться

Это основано на дате и добавляет случайный суффикс для «обеспечения» уникальности. Хорошо работает для идентификаторов css. Он всегда возвращает что-то вроде и легко взломать:

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;
        };
8
ответ дан ling 19 August 2018 в 08:22
поделиться

Это создаст UUID версии 4 (созданный из псевдослучайных чисел):

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

Вот пример сгенерированных UUID:

682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136
19
ответ дан Mathieu Pagé 19 August 2018 в 08:22
поделиться

Было бы полезно использовать веб-службу.

Быстрое обнаружение Google: http://www.hoskinson.net/GuidGenerator/

Не может ручаться за эту реализацию, но кто-то должен опубликовать bonidide GUID generator.

С помощью такой веб-службы вы можете создать веб-интерфейс REST, который использует веб-службу GUID, и служит через AJAX для javascript в браузере.

28
ответ дан Sean 19 August 2018 в 08:22
поделиться
  • 1
    Я сделал, принимаю и использую этот: timjeanes.com/guid . Он использует .NET для создания нового GUID и возвращает его без какого-либо дополнительного пуха. Он также будет работать над JSONP. – teedyay 2 June 2010 в 21:35
  • 2
    На самом деле, веб-служба, чтобы служить GUID? Это почти так же странно, как написание веб-службы для обслуживания случайных чисел - если только вам не нужны действительно действительно случайные числа, созданные некоторым источником физического шума, подключенным к серверу. – Pierre Arnaud 9 September 2014 в 07:21
  • 3
    Единственная проблема с сетевым сервисом заключается в том, что сеть может быть отключена. – Gustav 26 December 2017 в 20:09
  • 4
    Ссылка устарела, обслуживание не работает. – Marecky 4 March 2018 в 19:16

Настроил мой собственный генератор UUID / GUID с некоторыми дополнительными функциями здесь .

Я использую следующий генератор случайных чисел Kybos , чтобы быть немного более криптографически звучит.

Ниже мой сценарий с методами Mash и Kybos из baagoe.com исключен.

//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));
12
ответ дан Tracker1 19 August 2018 в 08:22
поделиться

Проект JavaScript на GitHub - https://github.com/LiosK/UUID.js

UUID.js Генератор UUID, совместимый с RFC для JavaScript.

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

Возможности Создает совместимые с RFC 4122 UUID.

Версии 4 UUID (UUID от случайных чисел) и UUID с 1-й версией (UUID с учетом времени).

Объект UUID допускает разнообразный доступ к UUID, включая доступ к полям UUID.

Низкое временное разрешение JavaScript компенсируется случайными числами.

20
ответ дан Wojciech Bednarski 19 August 2018 в 08:22
поделиться

Вы можете использовать node-uuid ( https://github.com/kelektiv/node-uuid )

Простая, быстрая генерация RFC4122 UUIDS.

Особенности:

  • Создать RFC4122 версии 1 или версии 4 UUIDs
  • Запускается в узлах.js и браузерах.
  • Криптографически сильная случайная генерация # на поддерживающих платформах.
  • Малая занимаемая площадь (хотите что-то меньшее? Проверьте это! )

Установка с помощью NPM:

npm install uuid

Или Использование uuid через браузер:

Загрузите исходный файл (uuid v1): https: //raw.githubusercontent. com / kelektiv / node-uuid / master / v1.js Загрузите исходный файл (uuid v4): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js


Хотите еще меньше? Проверьте это: https://gist.github.com/jed/982883


Использование:

// 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'
69
ответ дан 4 revs 19 August 2018 в 08:22
поделиться
  • 1
    Исходный файл мертв. – Edward Olamisan 13 April 2017 в 03:50
  • 2
    @Edward Olamisan Обновлен новый источник для замены устаревшей версии. – Kyros Koh 14 April 2017 в 21:31
  • 3
    Это правильный ответ, тбх. Просто используйте эту библиотеку. – justin.m.chase 20 May 2017 в 05:29
  • 4
    Версия ES6: import uuid from 'uuid/v4'; let id = uuid(); – justin.m.chase 20 May 2017 в 05:30
  • 5
    Это не UUID? – Marco Kerwitz 27 December 2017 в 00:28
  • 6
    Нет. UUID / GUID - это 122-разрядный (+ 6 зарезервированных бит) номер. это может гарантировать уникальность через глобальную службу встречных операций, но часто она реле вовремя, MAC-адрес и случайность. UUID не случайны! UID, который я предлагаю здесь, не полностью сжат. Вы можете сжать его до 122-битного целого числа, добавить 6 предопределенных бит и дополнительных случайных битов (удалить несколько бит таймера), и вы получите совершенно сформированный UUID / GUID, который вам тогда придется преобразовать в hex. Для меня это не добавляет ничего, кроме соответствия длине идентификатора. – Simon Rigét 18 February 2018 в 01:05
  • 7
    Релевание по MAC-адресам для уникальности на виртуальных машинах - плохая идея! – Simon Rigét 18 February 2018 в 01:48
  • 8
    @ justin.m.chase не должно быть const id = uuid – Kermit_ice_tea 22 February 2018 в 02:07
73
ответ дан 4 revs 30 October 2018 в 20:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: