Метод Math.random() в JavaScript

На самом деле не совсем случайных

Метод Math.random() в JavaScript

Пока вы думаете, что получаете по‑настоящему случайное число, JavaScript запускает определённый алгоритм: применяет математическую формулу и генерирует значение, которое лишь выглядит как случайность.

В этой статье разберём, как работает Math.random(), почему он всегда возвращает числа меньше 1 и как быть, если требуется криптографически стойкий рандом.

Что такое Math.random() в JavaScript?

Math.random() — это встроенный метод JavaScript, который возвращает псевдослучайное число с плавающей точкой от 0 (включительно) до 1 (не включительно).

Как работает метод Math.random()

Math.random() работает на основе псевдослучайного генератора (PRNG — Pseudo-Random Number Generator). Это значит, что вся «случайность» — результат математической формулы. Алгоритм запускается от некоторого начального значения — сида (seed) — и даёт последовательность чисел, которые выглядят случайными, но при желании её можно воспроизвести.

Диапазон возвращаемых значений (от 0 до 1)

Каждый вызов Math.random() возвращает число в диапазоне 0 ≤ x < 1. То есть 0 может попасться (редко, но может), а вот 1 вообще никогда.

Например: 

console.log(Math.random());
Диапазон возвращаемых значений (от 0 до 1)

Почему меньше одного? Потому что так устроена внутренняя логика распределения чисел. Это удобно для масштабирования — умножаем на нужный диапазон и получаем значения от 0 до N, исключая крайний случай.

Полезный блок со скидкой

Если вам интересно разбираться со смартфонами, компьютерами и прочими гаджетами и вы хотите научиться создавать софт под них с нуля или тестировать то, что сделали другие, — держите промокод Практикума на любой платный курс: KOD (можно просто на него нажать). Он даст скидку при покупке и позволит сэкономить на обучении.

Бесплатные курсы в Практикуме тоже есть — по всем специальностям и направлениям, начать можно в любой момент, карту привязывать не нужно, если что.

Базовое использование Math.random()

Простой пример генерации случайного числа

Начнём с самого простого, с синтаксиса метода Math.random():

Math.random()

Он вызывается без аргументов, и в результате мы получаем число с плавающей точкой от 0 (включительно) до 1 (не включительно). На каждый вызов — новое число. 

Если нужно просто посмотреть результат — можно сразу вызвать метод в console.log(). Но чаще всего это значение требуется использовать дальше: передать в функцию, умножить на диапазон, округлить, сравнить, сохранить для расчётов и т. д. В таких случаях его лучше положить в переменную:

// Генерируем число и сохраняем в переменную
let randomNumber = Math.random();
// Теперь можем работать с этим числом дальше
console.log(randomNumber); 
Простой пример генерации случайного числа

Теперь randomNumber — это наше случайное значение, с которым можно строить дальнейшую логику. Например:

  • умножить на 10, чтобы получить число от 0 до 10;
  • преобразовать в целое с Math.floor();
  • проверить, больше ли оно 0,5, и принять решение;
  • использовать как индекс для случайного выбора из массива.

Более интересные примеры рассмотрим в следующих разделах.

Почему числа всегда меньше 1

Каждое значение, которое возвращает Math.random(), всегда меньше 1, потому что по стандарту ECMAScript верхняя граница не включается. Да, можно получить 0,000000000000001, но не 1,0000000000. Даже если миллион раз вызвать — не выйдет.

Это сделано специально, чтобы исключить граничный случай, где результат умножения, например, Math.random() * 10 мог бы случайно превратиться в 10 и сломать вам всю логику округления с Math.floor().

Представьте, вы делаете выбор из 10 элементов в массиве по индексу:

let index = Math.floor(Math.random() * 10);

Здесь мы умножаем случайное число от 0 до <1 на 10, а потом округляем его вниз. Это даёт значения от 0 до 9 — подходит для массива из 10 элементов (array[0] до array[9]).

Но если бы Math.random() возвращал ровно 1, то было бы так:

Math.floor(1 * 10) === 10

Здесь array[10] уже за пределами массива. Ошибка, грусть, undefined. Поэтому верхняя граница и отрезается.

Как получить случайное число в заданном диапазоне

Math.random() сам по себе — это просто число от 0 до 1. Но в реальной жизни нам обычно нужно что-то более осмысленное: случайный номер заказа, рандомный индекс массива, дробное значение в заданных границах и т. п. Разберёмся, как превратить Math.random() в полезный инструмент.

Формула для целых чисел

Для получения случайного целого числа от min до max включительно используют такую формулу:

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

Вот что здесь происходит:

  • Math.random() генерирует число от 0 до 0,999…
  • * (max – min + 1) растягивает диапазон, чтобы попасть в нужную длину (например, от 1 до 10 = 10 чисел, а не 9);
  • Math.floor() округляет вниз, чтобы получить целое;
  • + min сдвигает всё так, чтобы диапазон начинался не с нуля, а с нужного минимума.

Почему в формуле +1 ? Потому что Math.random() никогда не возвращает 1, а Math.floor() всегда округляет вниз. Без +1 вы бы никогда не получили max, только max – 1.

getRandomInt(1, 10); // может вернуть 1, 2, 3 … 10
Как получить случайное число в заданном диапазоне
getRandomInt(0, 99); // от 0 до 99
Как получить случайное число в заданном диапазоне
getRandomInt(5, 5); // всегда 5, но формула всё равно работает
Как получить случайное число в заданном диапазоне

Генерация дробных чисел с точностью

Иногда нужно не целое число, а дробное — например, вероятность выпадения чего-то, плавающее значение в расчётах или просто скидка с двумя знаками после запятой. Для этого есть несколько способов.

Первый вариант самый простой. Чтобы получить любое дробное число в диапазоне, без контроля точности, используют базовую формулу:

function getRandomFloat(min, max) {
  return Math.random() * (max - min) + min;
}
Как получить случайное число в заданном диапазоне

Работает отлично, но количество знаков после точки случайное и неудобное.

Второй способ — это формула с контролем точности. Если нам нужно, чтобы в результате было ровно 2 знака, или 3, или 4, то используется такая функция:

function getRandomFloat(min, max, decimals = 2) {
  // Генерируем случайное число в диапазоне от min до max
  const random = Math.random() * (max - min) + min;
  // Округляем число до нужного количества знаков после запятой (в виде строки)
  const str = random.toFixed(decimals);
  // Преобразуем строку обратно в число с плавающей точкой и возвращаем
  return parseFloat(str);
}

При вызове функции мы прописываем диапазон и количество знаков после запятой. Два знака:

Как получить случайное число в заданном диапазоне

Три знака:

Как получить случайное число в заданном диапазоне

Четыре знака:

Как получить случайное число в заданном диапазоне

Метод .toFixed() возвращает строку, поэтому используем parseFloat() или + перед ней, чтобы снова получить число. Такой способ проще и отлично подходит для несложных повседневных задач.

Примеры диапазонов (1–10, 0–100 и др.)

Мы уже разобрали, как получить случайное целое число с помощью getRandomInt(min, max) и как сгенерировать дробное число — простой способ и с заданной точностью через getRandomFloat(min, max, decimals). Во всех этих функциях мы явно задаём диапазон: от какого числа и до какого (min и max). А дальше — дело техники. 

Ниже собрали набор готовых примеров для самых частых случаев из жизни:

// Целое от 1 до 10
getRandomInt(1, 10);
// Целое от 0 до 99
getRandomInt(0, 99);
// Только 0 или 1 (например, симуляция монетки: орёл или решка)
getRandomInt(0, 1);
// Целое от −10 до 35 (например, температура)
getRandomInt(-10, 35);
// Дробное от 0 до 1 (по сути, просто Math.random())
Math.random();
// Дробное от 5,5 до 7,8 с двумя знаками после запятой
getRandomFloat(5.5, 7.8, 2);
// Процент от 0 до 100 с двумя знаками
getRandomFloat(0, 100, 2);
// Рандомный час от 0 до 23
getRandomInt(0, 23);

Для целых чисел используем Math.floor() и +1, чтобы включить max. Для дробных — можно действовать через toFixed() и parseFloat, либо через множитель (как в getRandomFloat).

Практическое применение

Сила Math.random() раскрывается, когда вы добавляете к нему немного логики: выбираете элемент из массива, красите фон, бросаете виртуальные кости или генерируете моковые айдишники.

Случайный выбор элемента из массива

Допустим, у нас есть массив и мы хотим вытащить из него случайный элемент. Неважно, что внутри: цитаты, картинки, цвета, еда на ужин.

Например, есть массив с едой:

const items = [‘🍕’, ‘🍔’, ‘🍣’, ‘🌮’, ‘🥗’];

Берём Math.random(), умножаем на длину массива, округляем вниз — и получаем валидный индекс:

const randomItem = items[Math.floor(Math.random() * items.length)];
console.log(randomItem);
Случайный выбор элемента из массива

Работает везде: подходит для ротации баннеров, показа случайных отзывов или цитат, выбора цвета или фона.

Генерация случайного цвета (HEX, RGB)

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

Цвет в вебе обычно представляют в двух форматах:

  1. HEX-формат — привычный #ff0022, короткий и используется почти везде.
  2. RGB-формат — rgb(255, 0, 34), читается лучше, удобно для плавных переходов и анимаций.

Какой вариант использовать — зависит от задач. Дальше посмотрим, как их сгенерировать с помощью Math.random().

Для генерации HEX-цвета можно воспользоваться такой формулой:

function getRandomHexColor() {
  // Генерируем случайное число от 0 до 16777215 (в десятичной системе) 
  const hex = Math.floor(Math.random() * 0xffffff).toString(16);
  // Преобразуем число в шестнадцатеричную строку и дополняем нулями слева, если длина меньше 6 символов
  return `#${hex.padStart(6, '0')}`;
}

0xFFFFFF — это 16 777 215 в десятичной системе. Это максимальное значение для шестизначного HEX (#FFFFFF), то есть самого светлого цвета.

Цвет в формате HEX строится из трёх компонентов: красного (R), зелёного (G) и синего (B). Каждый из них занимает 8 бит и принимает значения от 0 до 255, то есть 256 возможных значений на канал.

Если посчитать все возможные комбинации: 256 (R) × 256 (G) × 256 (B), то мы получим 16 777 216 цветов. Но так как отсчёт начинается с нуля, самое первое значение — это 0x000000 (чёрный), а последнее — 0xFFFFFF (белый). То есть нам нужно получить случайное число от 0 до 16 777 215 включительно, что даст все 16 777 216 возможных цветов.

Вызываем нашу функцию и получаем случайный HEX-цвет:

console.log(getRandomHexColor());
Генерация случайного цвета (HEX, RGB)

Теперь напишем функцию для генерации случайного цвета в формате RGB:

function getRandomRgbColor() {
  const r = Math.floor(Math.random() * 256); // от 0 до 255
  const g = Math.floor(Math.random() * 256);
  const b = Math.floor(Math.random() * 256);
  return `rgb(${r}, ${g}, ${b})`;
}

Цвет в формате RGB тоже состоит из трёх компонентов: красного (R), зелёного (G) и синего (B). Каждый из них — это целое число от 0 до 255, что соответствует 8 битам данных. Получается те же 16 777 216 возможных цветов, как и в HEX, просто записываются по-другому:

  • HEX: #FF8040
  • RGB: rgb(255, 128, 64)

Дальше мы вызываем Math.random() для каждого канала отдельно, умножаем на 256, округляем вниз и получаем целое число в нужном диапазоне.Теперь вызываем функцию — и получаем свеженький RGB-цвет в формате rgb(число, число, число), который можно сразу подставить в style.backgroundColor или в CSS:

console.log(getRandomRgbColor());
Генерация случайного цвета (HEX, RGB)

Создание простых игровых механик

Самое базовое, с чего часто начинают знакомство со случайностями, — это симуляция броска кубика. Идеально подходит для демо, тестов, да и просто чтобы оживить интерфейс. Здесь всё намного проще, чем с цветами, потому что есть всего 6 вариантов:

function rollDice() {
  return Math.floor(Math.random() * 6) + 1;
}

Рассмотрим по шагам:

  1. Math.random() выдаёт число от 0 до 0,999…
  2. Умножаем его на 6, получаем диапазон от 0 до 5,999…
  3. Дальше Math.floor() обрезает дробную часть и даёт 0–5.
  4. +1 сдвигает диапазон в нужную сторону: от 1 до 6.

console.log(rollDice());
Создание простых игровых механик

Вообще, в реальных проектах Math.random() почти никогда не используется напрямую — его оборачивают во вспомогательные функции:

  • getRandomInt(min, max) — для получения случайного числа в заданном диапазоне.
  • chooseRandom(array) — для выбора случайного элемента.
  • rollChance(probability) — например, шанс срабатывания скила или падения лута.

Потому что написать Math.random() * (max – min) + min легко. А вот написать это без ошибок на границах — это уже квест. Например, можно забыть +1, и max никогда не выпадет. Даже простые функции вроде «броска кубика» легко сломать на ровном месте, особенно если диапазоны нестандартные или логика чуть сложнее.

Поэтому нормальные разработчики (особенно в геймдеве) всегда оборачивают Math.random() во вспомогательные функции с понятным API, чтобы безопасно переиспользовать.

Генерация ID и случайных строк

Если нужно быстро сгенерировать случайный идентификатор, не устанавливая стороннюю библиотеку, то Math.random() может выручить. Это удобно, когда нам нужен временный ключ, мы создаём уникальные значения в прототипе, работаем с моковыми данными или просто решаем задачку на собеседовании.

Выглядит это так:

const id = Math.random().toString(36).substring(2, 10);
console.log(id);

В этом коде:

  1. Math.random() даёт число от 0 до 1.
  2. .toString(36) переводит его в буквенно-цифровой формат, используя цифры и латинские буквы.
  3. .substring(2, 10) убирает “0.” и берёт 8 символов.

На выходе получаем короткую случайную строку, которую можно использовать как ID в моковых данных, ссылках, ключах и т. п.

Генерация ID и случайных строк

⚠️Никогда не используйте Math.random() для генерации токенов, паролей, ключей API, сессий и другой чувствительной информации. Этот метод криптографически небезопасен и может быть предсказуем при атаке. 

Альтернативы Math.random()

Как мы уже сказали выше, Math.random() хорош для простеньких игр, демо, UI‑тестов и прочих несекретных дел. Но если мы генерируем что-то чувствительное — токены доступа, пароли, ID для сессий или пользователей, одноразовые ссылки, — то Math.random() не подойдёт. 

Crypto.getRandomValues() для криптографически безопасных чисел

Если нужно получить настоящие случайные числа, пригодные для безопасности, используйте встроенное в браузер API:

crypto.getRandomValues(typedArray);

Этот метод возвращает по‑настоящему случайные числа — такие, которые сложно предсказать или взломать. Он используется в браузерах и генерирует значения на основе разных системных данных: энтропии, шума, движений курсора и прочих низкоуровневых штук.

// Создаём массив, который будем заполнять
const array = new Uint32Array(4); // 4 случайных числа от 0 до 2^32 - 1
// Заполняем его крипторандомными значениями
crypto.getRandomValues(array);
// Вызываем и получаем массив из чисел
console.log(array); 
Crypto.getRandomValues() для криптографически безопасных чисел

Uint32Array — это специальный типизированный массив, в котором хранятся 32-битные целые числа. Метод crypto.getRandomValues() берёт этот массив и перезаписывает все его значения случайными числами.

Да, под капотом crypto.getRandomValues() тоже использует псевдослучайный генератор (PRNG) — но с правильным сидом и достаточной энтропией. Это не просто «рандом», а рандом, которому можно доверять.

Библиотеки для расширенной генерации

Иногда Math.random() или даже crypto.getRandomValues() — это слишком низкоуровнево. Хочется просто сказать: выдай мне ID, собери строку из 8 символов, но только буквы и цифры — и всё. Тогда используют сторонние библиотеки: они дают надёжность, читаемость и отсутствие ошибок в логике генерации.

Рассмотрим три самые популярные.

UUID

UUID — это универсальный уникальный ID в формате xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Часто используется в бэкенде, но и во фронтенде тоже пригодится: для временных ключей, мок-данных, ссылок, генерации разных элементов и прочих мест, где важна уникальность.

Если вы работаете с Node.js или пишете фронтенд со сборщиком (Webpack, Vite и т. п.), то ставите зависимость npm install uuid, а потом используете её в проекте:

import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
console.log(id); // Например:  "b7bbf47c-1739-4f67-8d0f-168a12345abc"

Если нужно сгенерировать UUID на лету, например в консоли DevTools, на CodePen или в простом проекте, можно использовать встроенный метод:

let myuuid = crypto.randomUUID();
console.log('Your UUID is: ' + myuuid);
UUID

Это часть Web Crypto API, работает в безопасном контексте (https://, localhost) во всех современных браузерах.

Nano ID

Если нужно что-то более легковесное, то подойдёт генератор ​​Nano ID. Он весит всего 118 байт, использует расширенный алфавит A–Z, a–z, 0–9, _, и за счёт этого короче, чем UUID, но так же надёжен.

Устанавливаем через npm install nanoid и дальше импортируем в проект:

import { nanoid } from 'nanoid';
const id = nanoid();
console.log(id); // Например: "V1StGXR8_Z5jdHi6B-myT"

Можно задать длину ID или использовать собственный алфавит. Подойдет для генерации ID для DOM‑элементов, списков, UI‑объектов, ссылок или временных ключей.

faker-js

Библиотека @faker-js/faker — это целая экосистема для генерации любых фейковых данных: имён, адресов, компаний, мейлов и прочего. Но нас интересует генерация случайных чисел. Чтобы каждый раз не писать формулы для Math.random, в faker.number есть удобный API для генерации каких угодно чисел.

Устанавливаем через ​​npm install @faker-js/faker и импортируем в проект:

import { faker } from '@faker-js/faker';
// Целое число от 0 до 100
const randomInt = faker.number.int({ min: 0, max: 100 });
// Дробное число от 1,5 до 5,5 с точностью до сотых
const randomFloat = faker.number.float({ min: 1.5, max: 5.5, precision: 0.01 });

Если у вас большой проект с моками, тестами, автогенерацией интерфейсов, то faker может заменить кучу ручного кода и дать единый источник фейковых данных. Но если нужно просто сгенерировать пару чисел — возможно, проще обойтись Math.random() или чем-то полегче.

Частые ошибки и вопросы

Почему Math.random() не совсем случайный

Как мы уже говорили, в этом методе используется псевдослучайный генератор — PRNG (Pseudo-Random Number Generator). Он просто выполняет алгоритм, который даёт последовательность чисел, выглядящих случайными.

Алгоритм работает на базе начального значения, сида. В других языках можно задать сид самостоятельно и получить одинаковые результаты при каждом запуске (например, random.seed(5) в Python). В JS — такой возможности нет. Сид задаётся изнутри, и доступа к нему нет.

А почему вообще так? И почему это до сих пор не исправили?

Один из разработчиков JScript (движка JS в IE) так объяснял это решение: «В 90-х JavaScript создавался, чтобы заставить обезьянку на экране танцевать, когда двигаешь мышку. Никто не собирался писать на нём сложные системы, а уж тем более использовать криптографию».

Кроме того, тогда действовали жёсткие законы: криптография официально считалась военной технологией, и её «экспорт» в браузерах мог вызвать юридические проблемы. Поэтому Math.random() сделали простым и «безопасным» в смысле законодательства, а не криптографии.

Сегодня пересобрать это поведение уже нельзя, потому что это нарушит совместимость и может ввести в заблуждение (вроде бы Math.random() стал криптостойким, а на деле — нет). Поэтому Math.random() таким и остался: удобным, быстрым, но не для задач, где важна безопасность или уникальность.

Как избежать повторяющихся последовательностей

Если вы генерируете много значений подряд, особенно в короткий промежуток времени, может показаться, что числа повторяются или слишком «похожие». Это не баг, а особенность PRNG: иногда он реально выдаёт почти одинаковые числа.

Как избежать повторяющихся последовательностей

Чтобы избежать этого, делают так:

  • Используют вспомогательные обёртки: getRandomInt, getRandomFloat, shuffleArray.
  • Добавляют перемешивание: алгоритм Фишера — Йетса или другие.
  • Для максимального разнообразия используют crypto.getRandomValues() или сторонние библиотеки.

Даже в случайности нужна логика: если вы, например, делаете генератор лутбоксов и хотите, чтобы приз точно не повторился, — нужно вести список того, что уже выпало, и исключать это вручную. Math.random() сам этого не сделает.

Какие есть ограничения в плане безопасности случайных чисел

И вот тут повторим: Math.random() — это удобный, но небезопасный способ генерации чисел. Он не годится для токенов доступа, паролей, сессионных ключей, генерации важных уникальных ID, любых операций, где есть риск предсказуемости и атаки.

Алгоритм можно предугадать, если знать исходное состояние, и он не защищён от перебора или анализа. Это не теория — есть реальные атаки, основанные на слабости генератора случайных чисел. 

Например, в 2025 году была найдена критическая уязвимость (CVE‑2025‑7783) в популярной npm-библиотеке form-data, которая использовала Math.random() для генерации multipart boundary — специальной строки-разделителя в HTTP-запросах. Поскольку Math.random() предсказуем, атакующий мог вычислить эти границы и внедрить свои данные в запрос, обходя валидацию. Это приводило к выполнению произвольного кода и другим критическим проблемам безопасности.

Вывод? Если вы работаете с чем-то, где «случайность» влияет на безопасность — обязательно используйте криптоустойчивые методы. 

Вам слово

Приходите к нам в соцсети поделиться своим мнением о статье и почитать, что пишут другие. А ещё там выходит дополнительный контент, которого нет на сайте — шпаргалки, опросы и разная дурка. В общем, вот тележка, вот ВК — велком!

Обложка:

Алексей Сухов

Корректор:

Александр Зубов

Вёрстка:

Мария Климентьева

Соцсети:

Юлия Зубарева

Вам может быть интересно
easy