Хорошим местом для начала является JavaDocs . Они охватывают это:
Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:
- Вызов метода экземпляра нулевого объекта.
- Доступ или изменение поля нулевого объекта.
- Выполнение длины null, как если бы это был массив.
- Доступ или изменение слотов с нулевым значением, как если бы это был массив.
- Бросать нуль, как если бы это было значение Throwable.
Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.
blockquote>Также, если вы попытаетесь использовать нулевую ссылку с
synchronized
, который также выдаст это исключение, за JLS :SynchronizedStatement: synchronized ( Expression ) Block
blockquote>
- В противном случае, если значение выражения равно null,
NullPointerException
.Как это исправить?
Итак, у вас есть
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 = "";
Либо метод
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 ).
Было несколько попыток. Возникает вопрос: хотите ли вы иметь фактические 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"/>
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.
Math.random()*0xFFFFFFFF
должны быть Math.random()*0x100000000
для полной случайности, а вместо |0
следует использовать >>>0
, чтобы сохранить значения без знака (хотя с текущим кодом, я думаю, он получает далеко, даже если они подписаны). Наконец, в наши дни было бы очень неплохо использовать window.crypto.getRandomValues
, если это возможно, и вернуться к Math.random, только если это абсолютно необходимо. Math.random может иметь менее 128 бит энтропии, и в этом случае это будет более уязвимым для коллизий, чем это необходимо.
– Dave
18 July 2015 в 17:55
Самый быстрый 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
). 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)
. Сборка:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
. XXXXXXXX
и -XXXX-XXXX
. XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
. _p8(s)
, параметр s
сообщает функция, добавить ли тире или нет. _p8() + _p8(true) + _p8(true) + _p8()
и возвращаем его. Ссылка на этот пост в моем блоге
Наслаждайтесь! : -)
Для решения, совместимого с 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());
Мне очень нравится, насколько чистый ответ Бровафа , но, к сожалению, плохие реализации 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);
});
}
new Date().getTime()
не обновляется каждые миллисекунды. Я не уверен, как это влияет на ожидаемую случайность вашего алгоритма.
– devios1
18 March 2012 в 19:27
Date.now()
- new Date().getTime()
– Fresheyeball
28 June 2013 в 20:47
performance.now()
, не ограничены разрешением в один миллисекунду. Вместо этого они представляют собой числа с плавающей запятой с точностью до микросекундной точности . Кроме того, в отличие от Date.now, значения, возвращаемые функцией performance.now () , всегда увеличиваются с постоянной скоростью , независимо от системных часов, которые могут быть скорректированы вручную или искажены программным обеспечением, таким как Network Time Protocol.
– daniellmb
13 March 2014 в 06:25
Вот комбинация голосового ответа с обходным путем для столкновений 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 , если вы хотите проверить его.
, 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 просто предлагает достаточно большой набор ключей, чтобы уменьшить смену столкновений почти до нуля.
Я хотел понять ответ 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);
}
);
};
Простой модуль 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 "
blockquote> blockquote>
GUID
как string
выглядит как ok i>. Ваш ответ хотя бы решает более эффективное хранилище much i>, используя Uint16Array
. Функция toString
должна использовать двоичное представление в JavaScript object
– Sebastian
4 May 2014 в 12:03
_cryptoGuid
включить «4» в начале третьего раздела, например _guid
?
– row1
1 February 2015 в 22:05
Ну, у этого уже есть куча ответов, но, к сожалению, в связке нет «истинного» случайного. Нижеприведенная версия является адаптацией ответа 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);
});
};
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
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.
Вот решение от 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
)
}
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.");
}
);
Я знаю, это старый вопрос. Для полноты, если ваша среда - 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;
};
Лучший способ:
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}
образец ES6
const guid=()=> {
const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}
Из good ol 'wikipedia есть ссылка на javascript-реализацию UUID.
Он выглядит довольно элегантно и, возможно, может быть улучшен путем соления с хэшем Айпи адрес. Этот хэш, возможно, может быть вставлен в сервер html-документа для использования на стороне клиента javascript.
UPDATE: Исходный сайт имел перетасовку, вот обновленная версия
Странно, что никто не упомянул об этом пока, но для полноты, существует множество генераторов guid на npm . Я готов поспорить, что большинство из них также работают в браузере.
// 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('-');
Вот полностью несовместимая, но очень эффективная реализация для генерации уникального идентификатора 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');
Для тех, кто хочет иметь совместимое с 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("");
}
Вышеуказанная функция должна иметь приличный баланс между скоростью и случайностью.
Вот код, основанный на 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;
}
var s = new Array(36);
– MgSam
25 March 2013 в 22:03
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, если недействительно, возвращает пустое руководство.
Это основано на дате и добавляет случайный суффикс для «обеспечения» уникальности. Хорошо работает для идентификаторов 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;
};
Это создаст 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
Было бы полезно использовать веб-службу.
Быстрое обнаружение Google: http://www.hoskinson.net/GuidGenerator/
Не может ручаться за эту реализацию, но кто-то должен опубликовать bonidide GUID generator.
С помощью такой веб-службы вы можете создать веб-интерфейс REST, который использует веб-службу GUID, и служит через AJAX для javascript в браузере.
Настроил мой собственный генератор 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));
Проект 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 компенсируется случайными числами.
Вы можете использовать node-uuid ( https://github.com/kelektiv/node-uuid )
Простая, быстрая генерация RFC4122 UUIDS.
Особенности:
Установка с помощью 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'