Генерация случайных чисел в JavaScript — это получение непредсказуемого значения программным способом, чаще всего через встроенный метод Math.random(). Он подходит для игр, анимации, перемешивания списков и выбора случайного элемента, но не годится для паролей, токенов и ключей: там нужен криптостойкий генератор crypto.getRandomValues().
Содержание
Ниже разберу все рабочие приемы по порядку: число в диапазоне [0, 1), дробное и целое число в произвольном диапазоне [min, max], случайный элемент массива и криптостойкую генерацию. Затем — типичные ошибки. Весь код прогнан в Node.js 22; границы диапазонов проверены перебором.
Math.random(): число в диапазоне [0, 1)
Math.random() возвращает псевдослучайное число с плавающей точкой в полуинтервале [0, 1): ноль в результат попасть может, а единица — нет, верхняя граница строго исключена. Аргументов метод не принимает.
console.log(Math.random());
// например: 0.5097055147211202
// при каждом вызове число другое, всегда 0 <= x < 1
Проверить границы можно перебором: за миллион вызовов максимум остается меньше единицы, а минимум почти достигает нуля.
let min = 1, max = 0;
for (let i = 0; i < 1_000_000; i++) {
const r = Math.random();
if (r < min) min = r;
if (r > max) max = r;
}
console.log('максимум строго меньше 1:', max < 1); // true
Само по себе число из [0, 1) полезно редко — обычно его масштабируют под нужный диапазон.
Случайное дробное число в диапазоне [min, max)
Чтобы получить дробное число в диапазоне, результат Math.random() растягивают на ширину max - min и сдвигают на min. Нижняя граница входит в диапазон, верхняя — нет (наследуется от Math.random()).
function randomFloat(min, max) {
return Math.random() * (max - min) + min;
}
console.log(randomFloat(5, 10)); // например: 7.34..., всегда 5 <= x < 10
Формула работает и с отрицательными границами: randomFloat(-1, 1) даст число от -1 (включительно) почти до 1.
Случайное целое число в диапазоне [min, max]
Это частый сценарий: бросок кубика, номер вопроса, индекс. Здесь нужны обе границы включительно, поэтому к ширине диапазона прибавляют 1, а дробную часть отбрасывают через Math.floor:
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 6)); // целое от 1 до 6 включительно (бросок кубика)
Разберу, почему именно + 1. Math.random() дает число из [0, 1). Умножение на (max - min + 1) растягивает его до полуинтервала [0, max — min + 1), а Math.floor округляет вниз до целого — получаются значения от 0 до max - min включительно. Прибавляем min и накрываем весь диапазон, вместе с верхней границей.
Что обе границы реально достижимы, легко проверить перебором:
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
let lo = Infinity, hi = -Infinity;
for (let i = 0; i < 1_000_000; i++) {
const v = randomInt(1, 6);
if (v < lo) lo = v;
if (v > hi) hi = v;
}
console.log('минимум:', lo, 'максимум:', hi); // минимум: 1 максимум: 6
Важно: min и max должны быть целыми. Если передать дробные, Math.floor даст смещенные границы. Частный случай — монетка (0 или 1): Math.floor(Math.random() * 2).
Случайный элемент массива
Отдельная функция не нужна: берем случайный целый индекс от 0 до length - 1 и обращаемся по нему. Длина массива подставляется прямо в формулу, + 1 здесь не нужен, потому что индексация с нуля и последний индекс как раз length - 1.
const colors = ['красный', 'зеленый', 'синий'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
console.log(randomColor); // один из трех элементов массива
Так же выбирают случайный вопрос из списка, карту из колоды или реплику бота. Для полного перемешивания массива (а не выбора одного элемента) используют алгоритм Фишера-Йейтса — это отдельная задача.
Криптостойкие случайные числа: crypto.getRandomValues
Math.random() — это псевдослучайный генератор (PRNG). Его выход статистически ровный, но предсказуемый: зная состояние генератора, последовательность можно восстановить. Поэтому для паролей, токенов сессии, ключей и любых значений, влияющих на безопасность, Math.random() использовать нельзя.
Для таких задач есть Web Crypto API и метод crypto.getRandomValues(). Он заполняет типизированный массив криптостойкими случайными числами. Метод доступен в браузерах и в Node.js (глобальный объект crypto, начиная с версии 18).
const buffer = new Uint32Array(1);
crypto.getRandomValues(buffer);
console.log(buffer[0]); // целое от 0 до 4294967295
Тип массива задает диапазон значений каждого элемента: Uint8Array — байты 0..255, Uint16Array — 0..65535, Uint32Array — 0..4294967295 (есть и знаковые Int8Array, Int16Array, Int32Array). Криптостойкое целое в нужном диапазоне получают так:
function secureRandomInt(min, max) {
const range = max - min + 1;
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
return min + (buf[0] % range);
}
console.log(secureRandomInt(1, 6)); // криптостойкое целое от 1 до 6
Оговорка про границу: остаток от деления (%) вносит крохотный перекос, если range не делит 2^32 нацело. Для маленьких диапазонов он пренебрежимо мал, но для строгой равномерности применяют выборку с отбрасыванием (rejection sampling) — отбрасывают значения из «хвоста», который не делится на диапазон ровно. Для готового идентификатора удобнее crypto.randomUUID():
console.log(crypto.randomUUID()); // например: cdb9a702-9ffd-4ee1-b3f5-4b0f1b10f74d
Типичные ошибки
Забытый + 1 в формуле целого. Без него верхняя граница не достигается — max не выпадает никогда:
function randomIntWrong(min, max) {
return Math.floor(Math.random() * (max - min)) + min; // нет + 1
}
let hi = -Infinity;
for (let i = 0; i < 1_000_000; i++) {
const v = randomIntWrong(1, 6);
if (v > hi) hi = v;
}
console.log('максимум:', hi); // максимум: 5 - число 6 не появляется никогда
Исправление — вернуть + 1: Math.floor(Math.random() * (max - min + 1)) + min.
Math.round вместо Math.floor. Округление к ближайшему дает неравномерность: крайние значения выпадают вдвое реже, потому что к ним округляется только половина интервала.
const counts = {};
for (let i = 0; i < 3_000_000; i++) {
const v = Math.round(Math.random() * (3 - 1)) + 1; // 1..3 через round
counts[v] = (counts[v] || 0) + 1;
}
console.log(counts); // примерно { '1': 25%, '2': 50%, '3': 25% } - края реже
Исправление — всегда Math.floor с формулой (max - min + 1), которая дает равномерное распределение.
Math.random() для паролей и токенов. Псевдослучайный генератор предсказуем, поэтому такие значения уязвимы. Для всего, что связано с безопасностью, берут crypto.getRandomValues() или crypto.randomUUID().
Ожидание, что выпадет ровно max у дробной формулы. У randomFloat(min, max) верхняя граница исключена: значение может подойти к max вплотную, но не совпасть с ним. Если верхняя граница нужна включительно, работайте с целыми через randomInt.
FAQ
Можно ли задать сид (seed), чтобы Math.random() выдавал повторяемую последовательность? Нет, в стандартном JavaScript посева нет: результат нельзя воспроизвести между запусками. Если нужна повторяемость (например, для тестов), берут стороннюю библиотеку с сидом, например seedrandom.
Как округлить случайное число до нужного числа знаков после запятой? Метод .toFixed(2) вернет строку с двумя знаками; чтобы получить именно число, оберните результат в Number(...) или используйте Math.round(x * 100) / 100.
Чем crypto.getRandomValues() отличается от Math.random() по производительности? Криптостойкий генератор медленнее и работает с типизированными массивами, поэтому для игр и анимации оставляют Math.random(), а crypto подключают только там, где важна непредсказуемость.
Выводы
Math.random()возвращает дробное число в диапазоне [0, 1): ноль возможен, единица — нет.- Дробное число в диапазоне:
Math.random() * (max - min) + min(верхняя граница исключена). - Целое число в диапазоне включительно:
Math.floor(Math.random() * (max - min + 1)) + min—+ 1обязателен, иначеmaxне выпадет;Math.floor, а неMath.round, иначе края реже. - Случайный элемент массива:
arr[Math.floor(Math.random() * arr.length)]. - Для паролей, токенов и ключей
Math.random()небезопасен — используйтеcrypto.getRandomValues()илиcrypto.randomUUID().
Где применяется на практике
Генерация случайных чисел нужна почти в любом веб-проекте: случайный баннер на странице, перемешивание вопросов в тесте, механика в браузерной игре, а на стороне безопасности — токены и коды подтверждения. Ключевое умение здесь — выбрать инструмент под задачу: Math.random() для игровой случайности и crypto там, где значение нельзя предсказать.
Освойте тему на практике
Разобраться с методами, массивами и работой с числами в JavaScript с нуля помогает курс JavaScript Basic: на нем разбирают синтаксис языка, встроенные объекты и практику на реальных задачах.
Освойте тему на практике
Посмотреть, как преподаватели объясняют такие темы вживую, и задать свои вопросы можно на открытых вебинарах Otus — они бесплатные и проходят регулярно.
Смежные темы: Условный оператор if в JavaScript, Случайные числа в Python, Массивы в программировании.



