Math.random()
ES1+Returns a pseudo-random floating-point number in the half-open range [0, 1): 0 is possible, 1 is not. The sequence comes from a fast, non-cryptographic generator (xorshift128+ in major engines) that cannot be seeded and must never be used for security purposes.
Syntax
Math.random()Return Value
A random number between 0 (inclusive) and 1 (exclusive)
Examples
console.log(Math.random());
// 1부터 10 사이의 정수
console.log(Math.floor(Math.random() * 10) + 1); 📌 When to Use
Use Math.random() for randomness where unpredictability against an adversary does not matter: shuffling a playlist, picking a random tip or placeholder text, jittering retry delays to avoid thundering herds, spawning game entities, generating test data, A/B-style visual variation, and Monte Carlo estimations in casual tooling. The [0, 1) output is a building block you scale into what you need: Math.floor(Math.random() * n) for an integer 0 to n-1, min + Math.random() * (max - min) for a float range, and array[Math.floor(Math.random() * array.length)] for a uniform pick. Two boundaries define where it must not be used. First, security: session tokens, password-reset codes, OTPs, lottery draws, and anything an attacker profits from predicting require crypto.getRandomValues() or crypto.randomUUID(); Math.random's internal state can be recovered from a handful of outputs. Second, reproducibility: it cannot be seeded, so simulations, procedural generation, and property-based tests that must replay identically need a seedable PRNG (mulberry32, sfc32, or a library) instead. Within its lane it is excellent: fast, uniform enough for UI purposes, and available everywhere without imports.
⚠️ Common Mistakes
Using it for anything security-sensitive. The generator is deterministic and unseeded from a small internal state; published attacks reconstruct that state from observed outputs and predict every future value. Tokens, invite codes, captcha answers, and shuffle-based card games with stakes all require the Web Crypto API.
Off-by-one ranges: Math.random() * 10 never reaches 10, so Math.floor of it gives 0-9. For 1-10 you need Math.floor(Math.random() * 10) + 1. Inclusive-max integer ranges are Math.floor(Math.random() * (max - min + 1)) + min; forgetting the +1 silently excludes the maximum forever.
Rounding instead of flooring: Math.round(Math.random() * 10) makes 0 and 10 half as likely as the interior values, because each endpoint owns only half an interval. Distribution bugs like this are invisible in casual testing and show up as skewed analytics or unfair game drops.
Shuffling with sort: arr.sort(() => Math.random() - 0.5) is biased (comparison sorts assume consistent comparators, and element positions end up non-uniform) and even engine-dependent. The correct shuffle is Fisher-Yates, as in the example below.
Expecting it to hit 1, or treating 0 as impossible: the range is [0, 1), so code like if (Math.random() <= threshold) with threshold 0 still fires occasionally (0 is a valid output), and logic waiting for exactly 1 waits forever.
Assuming uniqueness: two calls can return equal values, and truncating output to a few digits (Math.random().toString(36).slice(2, 8)) collides far sooner than intuition suggests, thanks to the birthday paradox. IDs need crypto.randomUUID() or a counter component.
✅ Best Practices
Wrap the scaling recipes once: randomInt(min, max), randomFloat(min, max), pick(array), shuffle(array). Centralizing them eliminates per-call-site off-by-one arithmetic and gives you one place to swap in a seeded or crypto-backed source later.
Route security randomness through crypto: crypto.randomUUID() for IDs, crypto.getRandomValues(new Uint32Array(1)) for numeric entropy. Note that mapping crypto output to a range needs rejection sampling to avoid modulo bias, another reason to use vetted helpers.
For reproducible sequences (tests, procedural worlds, replays), use a small seedable PRNG like mulberry32 and store the seed; the same seed then regenerates the identical run, something Math.random() can never do.
Add jitter to retries and polling with randomness: delay = base * 2 ** attempt + Math.random() * base spreads client retries so a recovering server is not hammered in lockstep, a standard resilience pattern.
When randomness feeds UI, consider stability requirements: a random pick per render makes React/Svelte components flicker on re-render; generate once (per mount, per day, per user) and store the choice rather than re-rolling in the render path.
⚡ Performance Notes
Math.random() is very fast, tens of millions of calls per second per core, since xorshift128+ needs only a few integer operations and engines inline it; it will not bottleneck games, shuffles, or simulations at any realistic scale. It allocates nothing. crypto.getRandomValues() is slower per call and designed for batch use: request a whole typed array of values at once rather than one number per call, which amortizes the system entropy cost. For Monte Carlo workloads needing billions of samples, a hand-inlined seeded PRNG (mulberry32) can beat Math.random() slightly and adds reproducibility, but the gain is marginal; algorithmic improvements matter far more. One subtle cost to avoid: generating randomness inside render or layout code causes unnecessary re-renders and cache misses in UI frameworks, a structural cost unrelated to the generator itself.
🌍 Real World Example
Array Shuffle (Fisher-Yates)
Fisher-Yates is the canonical answer to "shuffle an array correctly": it walks from the last index down, swapping each element with a uniformly chosen earlier position (or itself), producing every permutation with equal probability in O(n) time. This example implements it non-destructively by copying first, the variant UI code usually wants. It is the algorithm behind card deals, quiz-question ordering, and playlist shuffle, and it exists precisely because the tempting sort-by-random-comparator one-liner is measurably biased.
function shuffleArray(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
const deck = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
console.log(shuffleArray(deck));
// ['7', 'K', '3', 'A', '9', '5', '2', 'Q', '10', '4', '8', 'J', '6']